### Line Style Tool
#
module Tools2D
class LinestyleTool2D

def db(string)
  dir=File.dirname(__FILE__) ### adjust folder to suit tool
  toolname="2Dtools"  ### adjust xxx to suit tool...
  locale=Sketchup.get_locale.upcase
  path=File.join(dir, toolname+locale+".lingvo")
  unless File.exist?(path)
     return string
  else
    deBabelizer(string,path)
  end 
end#def
def LinestyleTool2D::db(string)
  dir=File.dirname(__FILE__) ### adjust folder to suit tool
  toolname="2Dtools"  ### adjust xxx to suit tool...
  locale=Sketchup.get_locale.upcase
  path=File.join(dir, toolname+locale+".lingvo")
  unless File.exist?(path)
     return string
  else
    deBabelizer(string,path)
  end 
end#def

def getExtents
    bbox=Sketchup.active_model.bounds
    bbox.add(@ip.position)if @ip and @ip.valid?
    bbox.add(@ip1.position)if @ip1 and @ip1.valid?
    bbox.add(@ip2.position)if @ip2 and @ip2.valid?
    bbox.add(@ip3.position)if @ip3 and @ip3.valid?
    return bbox
end

@@cursor=nil
def initialize()
    @ip1 = nil
    @ip = nil
    @xdown = 0
    @ydown = 0
	@@cursor=nil
    curpath=File.join(File.dirname(__FILE__), "Icons", "2Dlinestyle_cursor.png")
    @@cursor=UI::create_cursor(curpath, 0, 31) if File.exist?(curpath)
end

def activate
    ### get/set reference plane 'z'
    @z=Sketchup.active_model.get_attribute("2Dtools","z",nil)
    Sketchup.active_model.set_attribute("2Dtools","z",0.0.mm)if not @z
    @z=Sketchup.active_model.get_attribute("2Dtools","z",nil)
    ###
    @ip1 = Sketchup::InputPoint.new
    @ip = Sketchup::InputPoint.new
    @drawn = false
    model=Sketchup.active_model
    if model.options["UnitsOptions"]["LengthUnit"]<=1 ### imperial = inches
      @width=model.get_attribute("2DLinestyle","width","1.0")
    else ### it's mm
      @width=model.get_attribute("2DLinestyle","width","25")
    end#if
    @style=model.get_attribute("2DLinestyle","style",(db("Continuous_____")))
    @color=model.get_attribute("2DLinestyle","color","Black")
    @edge=nil
    self.reset(nil)
    ###
end

def dialog()
    model=Sketchup.active_model
    if model.options["UnitsOptions"]["LengthUnit"]<=1 ### imperial = inches
      @width=model.get_attribute("2DLinestyle","width","1.0")
    else ### it's mm
      @width=model.get_attribute("2DLinestyle","width","25")
    end#if
    @style=model.get_attribute("2DLinestyle","style",(db("Continuous_____")))
    ###puts @style ##################
    @styleIN=@style
    @color=model.get_attribute("2DLinestyle","color","Black")
    ### check if existing custom styles
    @customstyles=model.get_attribute("2DLinestyle","customstyles",[])
    @customstyles=model.get_attribute("2DLinestyle","customstyles",[])
    customstyles=""
	@customstyles.sort.each{|a|customstyles<<"|"<<a[0]<<a[1]}if @customstyles[0]
    ###
    Sketchup::set_status_text((db("2D Line Style: Settings...")), SB_PROMPT)
    Sketchup::set_status_text("",SB_VCB_LABEL)
    ### settings
    prompts=[(db("Width: ")),(db("Style: ")),(db("Color: "))]
    values=[@width,@style,@color]
    ### set to suit units
    if model.options["UnitsOptions"]["LengthUnit"]<=1 ### imperial = inches
      widths="0.05|0.1|0.2|0.25|0.5|0.75|1.0|1.5|2.0|3.0|4.0|5.0|6.0|8.0|9.0|10|12|18|20|24|25|36|48|50|60|72|75|84|96|100|108|120|132|144"
    else ### it's mm
      widths="1|2|4|5|8|10|20|25|30|40|50|60|70|75|80|90|100|125|150|175|200|250|300|400|450|500|600|700|750|800|900|1000|1200|1500|1800|2100|2400|2700|3000|3300|3600"
    end#if
    ###
	styles=(db("Continuous_____|Dot. . . . . . .|Dashed- - - - -|Hidden-- -- -- --|DashDot- . - . - . -|Center-- - -- - --|Phantom--- -- ---|Divide-- .. -- .. --|< Custom Style >"))+customstyles
    materials=model.materials
	colors=[]; materials.each{|m|colors.push(m.display_name)}
	colors=colors+(Sketchup::Color.names.sort!)
	colors.uniq!; colors=colors.join("|")
	### dialog...
    popups=[widths,styles,colors]
    title=(db("2D Line Style Settings"))
    results=inputbox(prompts,values,popups,title)
    if not results
      self.deactivate(nil)
      return nil
    else
      @width,@style,@color=results
      ###
      model.set_attribute("2DLinestyle","width",@width)
      model.set_attribute("2DLinestyle","color",@color)
      if @style==(db("< Custom Style >"))
        @style=@styleIN
        model.set_attribute("2DLinestyle","style",@styleIN)
        self.custom_dialog()
        return nil
      end#if
      model.set_attribute("2DLinestyle","style",@style)
      ###
      self.reset(nil)
    end#if
end#dialog

def custom_dialog()
  model=Sketchup.active_model
  Sketchup::set_status_text((db("2D Line Style: Custom Line Style...")), SB_PROMPT)
  Sketchup::set_status_text("",SB_VCB_LABEL)
  ### settings
  prompts=[(db("Style Name: ")),(db("Style Pattern: "))]
  name=(db("MyStyle"))
  pattern="..    ..   "
  values=[name,pattern]
  popups=["",""]
  title=(db("2D Line Style Custom Line Style"))
  results=inputbox(prompts,values,popups,title)
  if not results
    model.set_attribute("2DLinestyle","style",@styleIN)
    @style=@styleIN
    self.dialog()
    return nil
  else
    name,pattern=results
    name=name.tr("~","").tr("|","") ### strip any ~ | from new name
    name=name+"~" ### e.g MyLineStyle~ + ... . etc
    customstyles=model.get_attribute("2DLinestyle","customstyles",[])
    names=[]
	customstyles.sort.each{|a|names<<a[0]}
    ### check pattern is dot+gap otherwise
    badpattern=false
    pattern.split("").each{|e|
      if e !=" " and e !="." or (pattern.split("")[0] !="." or pattern.split("")[-1] !=" ") 
        badpattern=true
        break
      end#if
    }
    if badpattern
      UI.messagebox("'"+pattern+"'\n\n"+(db("Pattern must be only dots and spaces (. )"))+"\n"+(db("and start with a dot and end with a space !"))+"\n\n\n"+"\n\n\n")
      self.custom_dialog()
      return nil
    end#if
    if pattern=="" ### the patterned is to be deleted
      UI.messagebox((db("Custom Line Style '"))+name+"'\n\n"+(db("has been removed from the list.")))
      tstyles=customstyles
      0.upto(customstyles.length-1)do |i|
        tstyles[i]=nil if tstyles[i][0]==name
      end#do
      customstyles=tstyles.compact!
      model.set_attribute("2DLinestyle","customstyles",customstyles)  
      model.set_attribute("2DLinestyle","style",@styleIN)
      self.dialog()
      return nil
    elsif name==(db("< Custom Style >")) ### foolproofing !!!
      UI.messagebox((db("Custom Line Style cannot be named '< Custom Style >'"))+"\n\n"+(db("try again.")))
      self.custom_dialog()
      return nil
    elsif names.include?(name)
      if UI.messagebox(name+"\n'"+pattern+"'\n\n"+(db("exists !"))+"\n\n"+(db("Overwrite it ?"))+"\n\n",MB_YESNO,"")==6
        ### 6=YES 7=NO
        tstyles=[]
        0.upto(customstyles.length-1)do |i|
          if customstyles[i][0]==name
            tstyles<<[name,pattern] ### omits old name,patt version
          else
            tstyles<<i ### adds all others back in
          end#if
        end#do
        customstyles=tstyles
        model.set_attribute("2DLinestyle","customstyles",customstyles)
      else
        self.custom_dialog()
        return nil
      end#if
    else ### new name
      customstyles<<[name,pattern]
      model.set_attribute("2DLinestyle","customstyles",customstyles)
    end#if
    ### reset and go back to where we were
    @style=name+pattern
    model.set_attribute("2DLinestyle","style",@style)
    self.dialog()
    return nil
    ###
  end#if
  ###
end#def

def deactivate(view)
    view.invalidate if @drawn and view
    @edge=nil
    Sketchup::set_status_text("",SB_PROMPT)
    Sketchup::set_status_text("",SB_VCB_LABEL)
    Sketchup::set_status_text("",SB_VCB_VALUE)
end

def reset(view)
    Sketchup::set_status_text((db("2D Line Style: "))+@width+" "+@style+" "+@color+ (db(". Right-Click(empty-space)=Settings-Dialog. <Enter>/Double-Click=End.")), SB_PROMPT)
    Sketchup::set_status_text("",SB_VCB_LABEL)
    @ip.clear
    @ip1.clear
    if view 
      view.tooltip = nil
      view.invalidate if @drawn
    end
    @edge=nil
    @drawn = false
end

def onReturn(view)
    view.invalidate
    Sketchup::set_status_text("",SB_PROMPT)
    Sketchup.send_action("selectSelectionTool:")
end

def onLButtonDoubleClick(flags, x, y, view)
    view.invalidate
    Sketchup::set_status_text("",SB_PROMPT)
    Sketchup.send_action("selectSelectionTool:")
end

def onSetCursor()
    #return nil if RUBY_PLATFORM =~ /darwin/
	UI::set_cursor(@@cursor)if @@cursor
end

def onRButtonDown(flags, x, y, view)
  view.model.selection.clear
  self.reset(view)
end

def onRButtonUp(flags, x, y, view)
  view.model.selection.clear
  return self.dialog()
end

def onMouseMove(flags, x, y, view)
    view.model.selection.clear
    Sketchup::set_status_text((db("2D Line Style: "))+@width+" "+@style+" "+@color+ (db(". Right-Click(empty-space)=Settings-Dialog. <Enter>/Double-Click=End.")), SB_PROMPT)
    Sketchup::set_status_text("",SB_VCB_LABEL)
    @ip.pick view, x, y
    if @ip != @ip1
        view.invalidate if @ip.display? or @ip1.display?
        @ip1.copy! @ip
        view.tooltip = @ip1.tooltip
    end
    # Check if the mouse was moved far enough to find another line.
    # This is used so that you can pick lines by dragging
    if @click and (x-@xdown).abs > 10 || (y-@ydown).abs > 10
        @dragging=true
    end
    if @click and @dragging
        @edge=self.edge_below_mouse_drag(view,x,y)
        self.style_line(view)if @edge
    end#if
end

def onLButtonDown(flags, x, y, view)
    view.model.selection.clear
    @ip1.pick view, x, y
    if @ip1.valid?
        @click=true
        p1=@ip1.position;p1.z=@z
        Sketchup::set_status_text((db("2D Line Style: "))+@width+" "+@style+" "+@color+ (db(". Right-Click(empty-space)=Settings-Dialog. <Enter>/Double-Click=End.")), SB_PROMPT)
        Sketchup::set_status_text("",SB_VCB_LABEL)
        @xdown = x
        @ydown = y
    end
    ### check if extg edge
    ph=view.pick_helper
    ph.do_pick(x,y)
    picked_edge=ph.picked_edge
    ###@edge=nil
    @edge=picked_edge if picked_edge
    ###
    self.style_line(view)if @edge
end

def onLButtonUp(flags, x, y, view)
    view.model.selection.clear
    @dragging=false
    @click=false
    Sketchup::set_status_text((db("2D Line Style: "))+@width+" "+@style+" "+@color+ (db(". Right-Click(empty-space)=Settings-Dialog. <Enter>/Double-Click=End.")), SB_PROMPT)
    Sketchup::set_status_text("",SB_VCB_LABEL)
end

def resume(view)
  view.invalidate
  Sketchup::set_status_text((db("2D Line Style: "))+@width+" "+@style+" "+@color+ (db(". Right-Click(empty-space)=Settings-Dialog. <Enter>/Double-Click=End.")), SB_PROMPT)
  Sketchup::set_status_text("",SB_VCB_LABEL)
end

def edge_below_mouse_drag(view, x, y)
    ph=view.pick_helper
    ph.do_pick(x, y, 10)
	ent=ph.best_picked
	if ent and ent.class==Sketchup::Edge
	    @ip.pick view, x, y
	    return ent
	else
		return nil
	end#if
end

def style_line(view)
  model=view.model
  model.start_operation(db("2D Line Style"))
  ### make layers if not existing
  layers=model.layers
  layernames=[]
  layers.each{|lay|layernames<<lay.name}
  if not layernames.include?("~2D-LINE-HIDN")
    @hidnlayer=layers.add("~2D-LINE-HIDN")
    pb=@hidnlayer.page_behavior=LAYER_IS_HIDDEN_ON_NEW_PAGES
    layers.each{|lay|@hidnlayer=lay if lay.name=="~2D-LINE-HIDN"}
    if model.pages.selected_page
      model.pages.selected_page.set_visibility(@hidnlayer,false)
    end#if
    @hidnlayer.visible=false
  else
    layers.each{|lay|@hidnlayer=lay if lay.name=="~2D-LINE-HIDN"}
    if model.pages.selected_page
      model.pages.selected_page.set_visibility(@hidnlayer,false)
    end#if
    @hidnlayer.visible=false
  end#if
  if not layernames.include?("~2D-LINE-STYL")
    @stylelayer=layers.add("~2D-LINE-STYL")
    pb=@stylelayer.page_behavior=LAYER_IS_VISIBLE_ON_NEW_PAGES
    model.pages.each{|p|p.set_visibility(@stylelayer,true)}
    if model.pages.selected_page
      model.pages.selected_page.set_visibility(@stylelayer,true)
    end#if
    @stylelayer.visible=true
  else
    layers.each{|lay|@stylelayer=lay if lay.name=="~2D-LINE-STYL"}
    if model.pages.selected_page
      model.pages.selected_page.set_visibility(@stylelayer,true)
    end#if
    @stylelayer.visible=true
  end#if
  ### make face group/compo dot
  @compo=LinestyleTool2D.make_dot("~2D~DOT")
  ### now have '@compo' building block dot for lines
  edges=[]
    if @edge.curve
      @edge.curve.edges.each{|e|edges<<e}
    else
      edges=[@edge]
    end#if
  edges.each{|e|
    @edge=e
    @p1=@edge.start.position
    @p2=@edge.end.position
    p2f=@p2.clone;p2f.z=@p1.z
    vec=p2f-@p1
    @ang=0
    if @p2.y>=@p1.y
      @ang=X_AXIS.angle_between(vec)
    elsif @p2.y<@p1.y
      @ang=360.degrees-(X_AXIS.angle_between(vec))
    end#if
    if model.options["UnitsOptions"]["LengthUnit"]<=1 ### imperial = inches
      @wid=@width.to_f ### in inches
    else ### in mm
      @wid=(@width+"mm").to_l.to_f
    end#if
    @len=@p1.distance(@p2)
    ### place instance over line...........................
    self.make_styled_line()
  }
  model.commit_operation
end

def LinestyleTool2D::make_dot(componame)
  model=Sketchup.active_model
  entities=model.active_entities ###v4
  defns=model.definitions
  defnames=[];defns.each{|defn|defnames<<defn.name}
  @compo=nil
  if not defnames.include?(componame)
    group=entities.add_group()
    w=0.5
    pts=[[0,0,0.4.mm],[0,w,0.4.mm], [1,w,0.4.mm],[1,0,0.4.mm], [1,-w,0.4.mm],[0,-w,0.4.mm]]
    face=group.entities.add_face(pts)
    face.reverse!
    inst=group.to_component()
    @compo=inst.definition
    inst.erase! if inst.valid?
    @compo.name=componame
    @compo.entities.each{|e|
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    @compo.casts_shadows=false
    @compo.receives_shadows=false
    @compo.behavior.always_face_camera=false
    @compo.behavior.is2d=true
    @compo.behavior.snapto=0  ### snaps to no surfaces
  else#already made
    @compo=nil;defns.each{|defn|@compo=defn if defn.name==componame}
  end#if
  ### now have '@compo' building block for lines
  return @compo
end#def


def make_styled_line()
  model=Sketchup.active_model
  if @edge
    ents=@edge.parent.entities
  else
    ents=model.active_entities ###v4.0
  end#if
  if /~/=~@style ### it's a custom style
    pattern=@style.split("~")[1] ### MyLineStyle~... .. . etc
    count=pattern.split("").length
    len=@len
    dot_len1=len/((len/@wid).floor)
    patt_len=dot_len1*count
    num_patts=(len/patt_len).ceil
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    lrun=0.inch
    num_patts.times do |this|
      pattern.split("").each{|e|
        if e=="."
          tr=Geom::Transformation.new(p0)
          inst=gents.add_instance(@compo,tr)
          tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
          inst.transform!(tr)
        end#if
        p0.offset!([1,0,0],dot_len1)
        lrun=lrun+dot_len1
        break if lrun >= len-dot_len1
      }
      break if lrun >= len-dot_len1
    end#times
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ### relocate    
    tr=Geom::Transformation.new(@p1)
    gp.transform!(tr)### move into place
    tr=Geom::Transformation.rotation(@p1,[0,0,1],@ang)
    gp.transform!(tr)### rotate to suit
### 3D transformation etc..............................................
 if @p1.z != @p2.z ### NOT flat
  if @p1.x==@p2.x and @p1.y==@p2.y ### vertical
    ### as it's vertical it will have initially been rotated to Y axis
    tr=Geom::Transformation.rotation(@p1,[1,0,0],90.degrees)
    gp.transform!(tr)
  else ### sloping
    p1=@edge.start.position
    p2=@edge.end.position
    p2f=p2.clone;p2f.z=p1.z
    vec=p2-p1
    vecf=p2f-p1
    ang3d=vecf.angle_between(vec)
    ang3d= -ang3d if p2.z<p1.z
    tr=Geom::Transformation.rotation(p1,[0,0,-1],90.degrees)
    p2f.transform!(tr)
    vecn=p2f-p1
    tr=Geom::Transformation.rotation(p1,vecn,ang3d)
    gp.transform!(tr)### rotate to suit in 3D
  end#if
 end#if
 ### make it rotated to suit any edge's face
    if @edge.faces[0]
      gface=nil;gents.each{|e|
        if e.class==Sketchup::Face
          gface=e; break
        end#if
      }
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      camera=model.active_view.camera
      eye=camera.eye
      target=camera.target
      vecc=eye-target ### reversed towards camera
      fface=@edge.faces[0]
      fangle=180.degrees ### worst case...
      @edge.faces.each{|face|
        fface=face if face.normal.angle_between(vecc)<fangle
        fangle=face.normal.angle_between(vecc)
      }
      fnormal=fface.normal
      ang=fnormal.angle_between(gnormal)
      vec=@p2-@p1
      tr=Geom::Transformation.rotation(@p1,vec,ang)
      gp.transform!(tr)
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      if gnormal != fnormal
        tr=Geom::Transformation.rotation(@p1,vec,ang*-2)
        gp.transform!(tr)
      end#if
      ### now shift onto the face IF it's not a conormal faced edge
      conormal=false
      if fface and @edge.faces[1]
        (@edge.faces-[fface]).each{|face|
          if face.normal==fnormal or face.normal.reverse==fnormal
            conormal=true;break
          end#if
        }
      end#if
      if not conormal ###if it's true we leave the styled-line centered
        ### find side of edge face is on...
        p1=@edge.start.position;p2=@edge.end.position
        pc=p1.clone;vec=p2-p1
        pc.offset!(vec,(p1.distance(p2))/2)
        pcc=pc.clone;vecc=vec.clone
        tr=Geom::Transformation.rotation(pc,fface.normal,90.degrees)
        vecc.transform!(tr);pcc.offset!(vecc,1.mm)
        vecc.reverse! if fface.classify_point(pcc)!=1
        p11=p1.clone;p11.offset!(vecc,@wid/2)
        gptrans=gp.transformation.to_a
        gptrans[12]=p11.x;gptrans[13]=p11.y;gptrans[14]=p11.z
        gp.transformation=gptrans
      end#if
    end#if
 ### end 3D .....................................................
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    @edge.layer=@hidnlayer if @edge
    ###
  elsif @style==(db("Continuous_____")) ########################################
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    tr=Geom::Transformation.new(p0)
    inst=gents.add_instance(@compo,tr)
    ### scale
    tr=Geom::Transformation.scaling(p0,@len,@wid,1)
    inst.transform!(tr)
    ### explode instance
    gents.to_a.each{|e|e.explode}
    ### place and rotate   
    tr=Geom::Transformation.new(@p1)
    gp.transform!(tr)### move into place
    tr=Geom::Transformation.rotation(@p1,[0,0,1],@ang)
    gp.transform!(tr)### rotate to suit
 ### 3D transformation etc..............................................
 if @p1.z != @p2.z ### NOT flat
  if @p1.x==@p2.x and @p1.y==@p2.y ### vertical
    ### as it's vertical it will have initially been rotated to Y axis
    tr=Geom::Transformation.rotation(@p1,[1,0,0],90.degrees)
    gp.transform!(tr)
    ### it's now facing 'front'...
  else ### sloping
    p1=@edge.start.position
    p2=@edge.end.position
    p2f=p2.clone;p2f.z=p1.z
    vec=p2-p1
    vecf=p2f-p1
    ang3d=vecf.angle_between(vec)
    ang3d= -ang3d if p2.z<p1.z
    tr=Geom::Transformation.rotation(p1,[0,0,-1],90.degrees)
    p2f.transform!(tr)
    vecn=p2f-p1
    tr=Geom::Transformation.rotation(p1,vecn,ang3d)
    gp.transform!(tr)### rotate to suit in 3D
  end#if
 end#if
 ### make it rotated to suit any edge's face
    if @edge.faces[0]
      gface=nil;gents.each{|e|
        if e.class==Sketchup::Face
          gface=e; break
        end#if
      }
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      camera=model.active_view.camera
      eye=camera.eye
      target=camera.target
      vecc=eye-target ### reversed towards camera
      fface=@edge.faces[0]
      fangle=180.degrees ### worst case...
      @edge.faces.each{|face|
        fface=face if face.normal.angle_between(vecc)<fangle
        fangle=face.normal.angle_between(vecc)
      }
      fnormal=fface.normal
      ang=fnormal.angle_between(gnormal)
      vec=@p2-@p1
      tr=Geom::Transformation.rotation(@p1,vec,ang)
      gp.transform!(tr)
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      if gnormal != fnormal
        tr=Geom::Transformation.rotation(@p1,vec,ang*-2)
        gp.transform!(tr)
      end#if
      ### now shift onto the face IF it's not a conormal faced edge
      conormal=false
      if fface and @edge.faces[1]
        (@edge.faces-[fface]).each{|face|
          if face.normal==fnormal or face.normal.reverse==fnormal
            conormal=true;break
          end#if
        }
      end#if
      if not conormal ###if it's true we leave the styled-line centered
        ### find side of edge face is on...
        p1=@edge.start.position;p2=@edge.end.position
        pc=p1.clone;vec=p2-p1
        pc.offset!(vec,(p1.distance(p2))/2)
        pcc=pc.clone;vecc=vec.clone
        tr=Geom::Transformation.rotation(pc,fface.normal,90.degrees)
        vecc.transform!(tr);pcc.offset!(vecc,1.mm)
        vecc.reverse! if fface.classify_point(pcc)!=1
        p11=p1.clone;p11.offset!(vecc,@wid/2)
        gptrans=gp.transformation.to_a
        gptrans[12]=p11.x;gptrans[13]=p11.y;gptrans[14]=p11.z
        gp.transformation=gptrans
      end#if
    end#if
 ### end 3D .....................................................
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    @edge.layer=@hidnlayer if @edge
    ### ###
  elsif @style==(db("Dot. . . . . . .")) ### |.,| ###########################
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*1
    patt_len=dot_len1+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if num_patts>0 and gap_len<@wid/8
      num_patts -=1
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if (dot_len1+(@wid/8)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    (1+num_patts).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(gap_len+dot_len1))
    end#times
=begin
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
=end
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ### relocate    
    tr=Geom::Transformation.new(@p1)
    gp.transform!(tr)### move into place
    tr=Geom::Transformation.rotation(@p1,[0,0,1],@ang)
    gp.transform!(tr)### rotate to suit
### 3D transformation etc..............................................
 if @p1.z != @p2.z ### NOT flat
  if @p1.x==@p2.x and @p1.y==@p2.y ### vertical
    ### as it's vertical it will have initially been rotated to Y axis
    tr=Geom::Transformation.rotation(@p1,[1,0,0],90.degrees)
    gp.transform!(tr)
  else ### sloping
    p1=@edge.start.position
    p2=@edge.end.position
    p2f=p2.clone;p2f.z=p1.z
    vec=p2-p1
    vecf=p2f-p1
    ang3d=vecf.angle_between(vec)
    ang3d= -ang3d if p2.z<p1.z
    tr=Geom::Transformation.rotation(p1,[0,0,-1],90.degrees)
    p2f.transform!(tr)
    vecn=p2f-p1
    tr=Geom::Transformation.rotation(p1,vecn,ang3d)
    gp.transform!(tr)### rotate to suit in 3D
  end#if
 end#if
 ### make it rotated to suit any edge's face
    if @edge.faces[0]
      gface=nil;gents.each{|e|
        if e.class==Sketchup::Face
          gface=e; break
        end#if
      }
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      camera=model.active_view.camera
      eye=camera.eye
      target=camera.target
      vecc=eye-target ### reversed towards camera
      fface=@edge.faces[0]
      fangle=180.degrees ### worst case...
      @edge.faces.each{|face|
        fface=face if face.normal.angle_between(vecc)<fangle
        fangle=face.normal.angle_between(vecc)
      }
      fnormal=fface.normal
      ang=fnormal.angle_between(gnormal)
      vec=@p2-@p1
      tr=Geom::Transformation.rotation(@p1,vec,ang)
      gp.transform!(tr)
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      if gnormal != fnormal
        tr=Geom::Transformation.rotation(@p1,vec,ang*-2)
        gp.transform!(tr)
      end#if
      ### now shift onto the face IF it's not a conormal faced edge
      conormal=false
      if fface and @edge.faces[1]
        (@edge.faces-[fface]).each{|face|
          if face.normal==fnormal or face.normal.reverse==fnormal
            conormal=true;break
          end#if
        }
      end#if
      if not conormal ###if it's true we leave the styled-line centered
        ### find side of edge face is on...
        p1=@edge.start.position;p2=@edge.end.position
        pc=p1.clone;vec=p2-p1
        pc.offset!(vec,(p1.distance(p2))/2)
        pcc=pc.clone;vecc=vec.clone
        tr=Geom::Transformation.rotation(pc,fface.normal,90.degrees)
        vecc.transform!(tr);pcc.offset!(vecc,1.mm)
        vecc.reverse! if fface.classify_point(pcc)!=1
        p11=p1.clone;p11.offset!(vecc,@wid/2)
        gptrans=gp.transformation.to_a
        gptrans[12]=p11.x;gptrans[13]=p11.y;gptrans[14]=p11.z
        gp.transformation=gptrans
      end#if
    end#if
 ### end 3D .....................................................
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    @edge.layer=@hidnlayer if @edge
    ### ###
  elsif @style==(db("Dashed- - - - -")) ### |..,| ###########################
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*2
    patt_len=dot_len1+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if num_patts>0 and gap_len<@wid/8
      num_patts -=1
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if (dot_len1+(@wid/8)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    (1+num_patts).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(gap_len+dot_len1))
    end#times
=begin
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
=end
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ### place and rotate  
    tr=Geom::Transformation.new(@p1)
    gp.transform!(tr)### move into place
    tr=Geom::Transformation.rotation(@p1,[0,0,1],@ang)
    gp.transform!(tr)### rotate to suit
### 3D transformation etc..............................................
 if @p1.z != @p2.z ### NOT flat
  if @p1.x==@p2.x and @p1.y==@p2.y ### vertical
    ### as it's vertical it will have initially been rotated to Y axis
    tr=Geom::Transformation.rotation(@p1,[1,0,0],90.degrees)
    gp.transform!(tr)
  else ### sloping
    p1=@edge.start.position
    p2=@edge.end.position
    p2f=p2.clone;p2f.z=p1.z
    vec=p2-p1
    vecf=p2f-p1
    ang3d=vecf.angle_between(vec)
    ang3d= -ang3d if p2.z<p1.z
    tr=Geom::Transformation.rotation(p1,[0,0,-1],90.degrees)
    p2f.transform!(tr)
    vecn=p2f-p1
    tr=Geom::Transformation.rotation(p1,vecn,ang3d)
    gp.transform!(tr)### rotate to suit in 3D
  end#if
 end#if
 ### make it rotated to suit any edge's face
    if @edge.faces[0]
      gface=nil;gents.each{|e|
        if e.class==Sketchup::Face
          gface=e; break
        end#if
      }
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      camera=model.active_view.camera
      eye=camera.eye
      target=camera.target
      vecc=eye-target ### reversed towards camera
      fface=@edge.faces[0]
      fangle=180.degrees ### worst case...
      @edge.faces.each{|face|
        fface=face if face.normal.angle_between(vecc)<fangle
        fangle=face.normal.angle_between(vecc)
      }
      fnormal=fface.normal
      ang=fnormal.angle_between(gnormal)
      vec=@p2-@p1
      tr=Geom::Transformation.rotation(@p1,vec,ang)
      gp.transform!(tr)
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      if gnormal != fnormal
        tr=Geom::Transformation.rotation(@p1,vec,ang*-2)
        gp.transform!(tr)
      end#if
      ### now shift onto the face IF it's not a conormal faced edge
      conormal=false
      if fface and @edge.faces[1]
        (@edge.faces-[fface]).each{|face|
          if face.normal==fnormal or face.normal.reverse==fnormal
            conormal=true;break
          end#if
        }
      end#if
      if not conormal ###if it's true we leave the styled-line centered
        ### find side of edge face is on...
        p1=@edge.start.position;p2=@edge.end.position
        pc=p1.clone;vec=p2-p1
        pc.offset!(vec,(p1.distance(p2))/2)
        pcc=pc.clone;vecc=vec.clone
        tr=Geom::Transformation.rotation(pc,fface.normal,90.degrees)
        vecc.transform!(tr);pcc.offset!(vecc,1.mm)
        vecc.reverse! if fface.classify_point(pcc)!=1
        p11=p1.clone;p11.offset!(vecc,@wid/2)
        gptrans=gp.transformation.to_a
        gptrans[12]=p11.x;gptrans[13]=p11.y;gptrans[14]=p11.z
        gp.transformation=gptrans
      end#if
    end#if
 ### end 3D .....................................................
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    @edge.layer=@hidnlayer if @edge
    ### ###
  elsif @style==(db("Hidden-- -- -- --")) ### |....,....| ###################
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*4
    patt_len=dot_len1+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if num_patts>0 and gap_len<@wid/10
      num_patts -=1
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if (dot_len1+(@wid/10)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    (1+num_patts).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(gap_len+dot_len1))
    end#times
=begin
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
=end
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ### place and rotate  
    tr=Geom::Transformation.new(@p1)
    gp.transform!(tr)### move into place
    tr=Geom::Transformation.rotation(@p1,[0,0,1],@ang)
    gp.transform!(tr)### rotate to suit
### 3D transformation etc..............................................
 if @p1.z != @p2.z ### NOT flat
  if @p1.x==@p2.x and @p1.y==@p2.y ### vertical
    ### as it's vertical it will have initially been rotated to Y axis
    tr=Geom::Transformation.rotation(@p1,[1,0,0],90.degrees)
    gp.transform!(tr)
  else ### sloping
    p1=@edge.start.position
    p2=@edge.end.position
    p2f=p2.clone;p2f.z=p1.z
    vec=p2-p1
    vecf=p2f-p1
    ang3d=vecf.angle_between(vec)
    ang3d= -ang3d if p2.z<p1.z
    tr=Geom::Transformation.rotation(p1,[0,0,-1],90.degrees)
    p2f.transform!(tr)
    vecn=p2f-p1
    tr=Geom::Transformation.rotation(p1,vecn,ang3d)
    gp.transform!(tr)### rotate to suit in 3D
  end#if
 end#if
 ### make it rotated to suit any edge's face
    if @edge.faces[0]
      gface=nil;gents.each{|e|
        if e.class==Sketchup::Face
          gface=e; break
        end#if
      }
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      camera=model.active_view.camera
      eye=camera.eye
      target=camera.target
      vecc=eye-target ### reversed towards camera
      fface=@edge.faces[0]
      fangle=180.degrees ### worst case...
      @edge.faces.each{|face|
        fface=face if face.normal.angle_between(vecc)<fangle
        fangle=face.normal.angle_between(vecc)
      }
      fnormal=fface.normal
      ang=fnormal.angle_between(gnormal)
      vec=@p2-@p1
      tr=Geom::Transformation.rotation(@p1,vec,ang)
      gp.transform!(tr)
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      if gnormal != fnormal
        tr=Geom::Transformation.rotation(@p1,vec,ang*-2)
        gp.transform!(tr)
      end#if
      ### now shift onto the face IF it's not a conormal faced edge
      conormal=false
      if fface and @edge.faces[1]
        (@edge.faces-[fface]).each{|face|
          if face.normal==fnormal or face.normal.reverse==fnormal
            conormal=true;break
          end#if
        }
      end#if
      if not conormal ###if it's true we leave the styled-line centered
        ### find side of edge face is on...
        p1=@edge.start.position;p2=@edge.end.position
        pc=p1.clone;vec=p2-p1
        pc.offset!(vec,(p1.distance(p2))/2)
        pcc=pc.clone;vecc=vec.clone
        tr=Geom::Transformation.rotation(pc,fface.normal,90.degrees)
        vecc.transform!(tr);pcc.offset!(vecc,1.mm)
        vecc.reverse! if fface.classify_point(pcc)!=1
        p11=p1.clone;p11.offset!(vecc,@wid/2)
        gptrans=gp.transformation.to_a
        gptrans[12]=p11.x;gptrans[13]=p11.y;gptrans[14]=p11.z
        gp.transformation=gptrans
      end#if
    end#if
 ### end 3D .....................................................
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    @edge.layer=@hidnlayer if @edge
    ### ###
  elsif @style==(db("DashDot- . - . - . -")) ### |..,.,..| ##################
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*2
    dot_len2=@wid*1
    patt_len=dot_len1+@wid+dot_len2+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if num_patts>0 and gap_len<@wid/10
      num_patts -=1
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if (dot_len1+(@wid/10)+dot_len2+(@wid/10)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    dash=true
    (2*(num_patts)).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      if dash
        dot_lenx=dot_len1
        dash=false
      else ### it's a dot
        dot_lenx=dot_len2
        dash=true
      end#if
      tr=Geom::Transformation.scaling(p0,dot_lenx,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(dot_lenx+gap_len))
    end#times
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ### place and rotate   
    tr=Geom::Transformation.new(@p1)
    gp.transform!(tr)### move into place
    tr=Geom::Transformation.rotation(@p1,[0,0,1],@ang)
    gp.transform!(tr)### rotate to suit
### 3D transformation etc..............................................
 if @p1.z != @p2.z ### NOT flat
  if @p1.x==@p2.x and @p1.y==@p2.y ### vertical
    ### as it's vertical it will have initially been rotated to Y axis
    tr=Geom::Transformation.rotation(@p1,[1,0,0],90.degrees)
    gp.transform!(tr)
  else ### sloping
    p1=@edge.start.position
    p2=@edge.end.position
    p2f=p2.clone;p2f.z=p1.z
    vec=p2-p1
    vecf=p2f-p1
    ang3d=vecf.angle_between(vec)
    ang3d= -ang3d if p2.z<p1.z
    tr=Geom::Transformation.rotation(p1,[0,0,-1],90.degrees)
    p2f.transform!(tr)
    vecn=p2f-p1
    tr=Geom::Transformation.rotation(p1,vecn,ang3d)
    gp.transform!(tr)### rotate to suit in 3D
  end#if
 end#if
 ### make it rotated to suit any edge's face
    if @edge.faces[0]
      gface=nil;gents.each{|e|
        if e.class==Sketchup::Face
          gface=e; break
        end#if
      }
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      camera=model.active_view.camera
      eye=camera.eye
      target=camera.target
      vecc=eye-target ### reversed towards camera
      fface=@edge.faces[0]
      fangle=180.degrees ### worst case...
      @edge.faces.each{|face|
        fface=face if face.normal.angle_between(vecc)<fangle
        fangle=face.normal.angle_between(vecc)
      }
      fnormal=fface.normal
      ang=fnormal.angle_between(gnormal)
      vec=@p2-@p1
      tr=Geom::Transformation.rotation(@p1,vec,ang)
      gp.transform!(tr)
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      if gnormal != fnormal
        tr=Geom::Transformation.rotation(@p1,vec,ang*-2)
        gp.transform!(tr)
      end#if
      ### now shift onto the face IF it's not a conormal faced edge
      conormal=false
      if fface and @edge.faces[1]
        (@edge.faces-[fface]).each{|face|
          if face.normal==fnormal or face.normal.reverse==fnormal
            conormal=true;break
          end#if
        }
      end#if
      if not conormal ###if it's true we leave the styled-line centered
        ### find side of edge face is on...
        p1=@edge.start.position;p2=@edge.end.position
        pc=p1.clone;vec=p2-p1
        pc.offset!(vec,(p1.distance(p2))/2)
        pcc=pc.clone;vecc=vec.clone
        tr=Geom::Transformation.rotation(pc,fface.normal,90.degrees)
        vecc.transform!(tr);pcc.offset!(vecc,1.mm)
        vecc.reverse! if fface.classify_point(pcc)!=1
        p11=p1.clone;p11.offset!(vecc,@wid/2)
        gptrans=gp.transformation.to_a
        gptrans[12]=p11.x;gptrans[13]=p11.y;gptrans[14]=p11.z
        gp.transformation=gptrans
      end#if
    end#if
 ### end 3D .....................................................
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    @edge.layer=@hidnlayer if @edge
    ### ###
  elsif @style==(db("Center-- - -- - --")) ### |....,..,....| ###############
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*4
    dot_len2=@wid*2
    patt_len=dot_len1+@wid+dot_len2+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if num_patts>0 and gap_len<@wid/10
      num_patts -=1
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if (dot_len1+(@wid/10)+dot_len2+(@wid/10)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    dash=true
    (2*(num_patts)).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      if dash
        dot_lenx=dot_len1
        dash=false
      else ### it's a dot
        dot_lenx=dot_len2
        dash=true
      end#if
      tr=Geom::Transformation.scaling(p0,dot_lenx,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(dot_lenx+gap_len))
    end#times
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ### place and rotate   
    tr=Geom::Transformation.new(@p1)
    gp.transform!(tr)### move into place
    tr=Geom::Transformation.rotation(@p1,[0,0,1],@ang)
    gp.transform!(tr)### rotate to suit
### 3D transformation etc..............................................
 if @p1.z != @p2.z ### NOT flat
  if @p1.x==@p2.x and @p1.y==@p2.y ### vertical
    ### as it's vertical it will have initially been rotated to Y axis
    tr=Geom::Transformation.rotation(@p1,[1,0,0],90.degrees)
    gp.transform!(tr)
  else ### sloping
    p1=@edge.start.position
    p2=@edge.end.position
    p2f=p2.clone;p2f.z=p1.z
    vec=p2-p1
    vecf=p2f-p1
    ang3d=vecf.angle_between(vec)
    ang3d= -ang3d if p2.z<p1.z
    tr=Geom::Transformation.rotation(p1,[0,0,-1],90.degrees)
    p2f.transform!(tr)
    vecn=p2f-p1
    tr=Geom::Transformation.rotation(p1,vecn,ang3d)
    gp.transform!(tr)### rotate to suit in 3D
  end#if
 end#if
 ### make it rotated to suit any edge's face
    if @edge.faces[0]
      gface=nil;gents.each{|e|
        if e.class==Sketchup::Face
          gface=e; break
        end#if
      }
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      camera=model.active_view.camera
      eye=camera.eye
      target=camera.target
      vecc=eye-target ### reversed towards camera
      fface=@edge.faces[0]
      fangle=180.degrees ### worst case...
      @edge.faces.each{|face|
        fface=face if face.normal.angle_between(vecc)<fangle
        fangle=face.normal.angle_between(vecc)
      }
      fnormal=fface.normal
      ang=fnormal.angle_between(gnormal)
      vec=@p2-@p1
      tr=Geom::Transformation.rotation(@p1,vec,ang)
      gp.transform!(tr)
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      if gnormal != fnormal
        tr=Geom::Transformation.rotation(@p1,vec,ang*-2)
        gp.transform!(tr)
      end#if
      ### now shift onto the face IF it's not a conormal faced edge
      conormal=false
      if fface and @edge.faces[1]
        (@edge.faces-[fface]).each{|face|
          if face.normal==fnormal or face.normal.reverse==fnormal
            conormal=true;break
          end#if
        }
      end#if
      if not conormal ###if it's true we leave the styled-line centered
        ### find side of edge face is on...
        p1=@edge.start.position;p2=@edge.end.position
        pc=p1.clone;vec=p2-p1
        pc.offset!(vec,(p1.distance(p2))/2)
        pcc=pc.clone;vecc=vec.clone
        tr=Geom::Transformation.rotation(pc,fface.normal,90.degrees)
        vecc.transform!(tr);pcc.offset!(vecc,1.mm)
        vecc.reverse! if fface.classify_point(pcc)!=1
        p11=p1.clone;p11.offset!(vecc,@wid/2)
        gptrans=gp.transformation.to_a
        gptrans[12]=p11.x;gptrans[13]=p11.y;gptrans[14]=p11.z
        gp.transformation=gptrans
      end#if
    end#if
 ### end 3D .....................................................
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    @edge.layer=@hidnlayer if @edge
    ### ###
  elsif @style==(db("Phantom--- -- ---")) ### |......,....,......| ##########
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*6
    dot_len2=@wid*4
    patt_len=dot_len1+@wid+dot_len2+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if num_patts>0 and gap_len<@wid/10
      num_patts -=1
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if (dot_len1+(@wid/10)+dot_len2+(@wid/10)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    dash=true
    (2*(num_patts)).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      if dash
        dot_lenx=dot_len1
        dash=false
      else ### it's a dot
        dot_lenx=dot_len2
        dash=true
      end#if
      tr=Geom::Transformation.scaling(p0,dot_lenx,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(dot_lenx+gap_len))
    end#times
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ### place and rotate   
    tr=Geom::Transformation.new(@p1)
    gp.transform!(tr)### move into place
    tr=Geom::Transformation.rotation(@p1,[0,0,1],@ang)
    gp.transform!(tr)### rotate to suit
### 3D transformation etc..............................................
 if @p1.z != @p2.z ### NOT flat
  if @p1.x==@p2.x and @p1.y==@p2.y ### vertical
    ### as it's vertical it will have initially been rotated to Y axis
    tr=Geom::Transformation.rotation(@p1,[1,0,0],90.degrees)
    gp.transform!(tr)
  else ### sloping
    p1=@edge.start.position
    p2=@edge.end.position
    p2f=p2.clone;p2f.z=p1.z
    vec=p2-p1
    vecf=p2f-p1
    ang3d=vecf.angle_between(vec)
    ang3d= -ang3d if p2.z<p1.z
    tr=Geom::Transformation.rotation(p1,[0,0,-1],90.degrees)
    p2f.transform!(tr)
    vecn=p2f-p1
    tr=Geom::Transformation.rotation(p1,vecn,ang3d)
    gp.transform!(tr)### rotate to suit in 3D
  end#if
 end#if
 ### make it rotated to suit any edge's face
    if @edge.faces[0]
      gface=nil;gents.each{|e|
        if e.class==Sketchup::Face
          gface=e; break
        end#if
      }
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      camera=model.active_view.camera
      eye=camera.eye
      target=camera.target
      vecc=eye-target ### reversed towards camera
      fface=@edge.faces[0]
      fangle=180.degrees ### worst case...
      @edge.faces.each{|face|
        fface=face if face.normal.angle_between(vecc)<fangle
        fangle=face.normal.angle_between(vecc)
      }
      fnormal=fface.normal
      ang=fnormal.angle_between(gnormal)
      vec=@p2-@p1
      tr=Geom::Transformation.rotation(@p1,vec,ang)
      gp.transform!(tr)
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      if gnormal != fnormal
        tr=Geom::Transformation.rotation(@p1,vec,ang*-2)
        gp.transform!(tr)
      end#if
      ### now shift onto the face IF it's not a conormal faced edge
      conormal=false
      if fface and @edge.faces[1]
        (@edge.faces-[fface]).each{|face|
          if face.normal==fnormal or face.normal.reverse==fnormal
            conormal=true;break
          end#if
        }
      end#if
      if not conormal ###if it's true we leave the styled-line centered
        ### find side of edge face is on...
        p1=@edge.start.position;p2=@edge.end.position
        pc=p1.clone;vec=p2-p1
        pc.offset!(vec,(p1.distance(p2))/2)
        pcc=pc.clone;vecc=vec.clone
        tr=Geom::Transformation.rotation(pc,fface.normal,90.degrees)
        vecc.transform!(tr);pcc.offset!(vecc,1.mm)
        vecc.reverse! if fface.classify_point(pcc)!=1
        p11=p1.clone;p11.offset!(vecc,@wid/2)
        gptrans=gp.transformation.to_a
        gptrans[12]=p11.x;gptrans[13]=p11.y;gptrans[14]=p11.z
        gp.transformation=gptrans
      end#if
    end#if
 ### end 3D .....................................................
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    @edge.layer=@hidnlayer if @edge
    ### ###
  elsif @style==(db("Divide-- .. -- .. --")) ### |....,.,.,....| ############
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*4
    dot_len2=@wid*1
    dot_len3=@wid*1
    patt_len=dot_len1+@wid+dot_len2+@wid+dot_len3+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=(dot_len1+dot_len2+dot_len3)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/3 ################### 3 gaps ###
    end#if
    if num_patts>0 and gap_len<@wid/10
      num_patts -=1
      dots_len=(dot_len1+dot_len2+dot_len3)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/3 ################### 3 gaps ###
    end#if
    if (dot_len1+(@wid/10)+dot_len2+(@wid/10)+dot_len1)>@len ###
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    dash=true
    dot=false
    (3*(num_patts)).times do |this|
    tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      if dash
        dot_lenx=dot_len1
        dash=false
        dot=true
      else ### its a dot
        if dot
          dot_lenx=dot_len2
          dot=false
        else
          dot_lenx=dot_len3
          dash=true
          dot=false
        end#if
      end#if
      tr=Geom::Transformation.scaling(p0,dot_lenx,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(dot_lenx+gap_len))
    end#times
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ### place and rotate   
    tr=Geom::Transformation.new(@p1)
    gp.transform!(tr)### move into place
    tr=Geom::Transformation.rotation(@p1,[0,0,1],@ang)
    gp.transform!(tr)### rotate to suit
### 3D transformation etc..............................................
 if @p1.z != @p2.z ### NOT flat
  if @p1.x==@p2.x and @p1.y==@p2.y ### vertical
    ### as it's vertical it will have initially been rotated to Y axis
    tr=Geom::Transformation.rotation(@p1,[1,0,0],90.degrees)
    gp.transform!(tr)
  else ### sloping
    p1=@edge.start.position
    p2=@edge.end.position
    p2f=p2.clone;p2f.z=p1.z
    vec=p2-p1
    vecf=p2f-p1
    ang3d=vecf.angle_between(vec)
    ang3d= -ang3d if p2.z<p1.z
    tr=Geom::Transformation.rotation(p1,[0,0,-1],90.degrees)
    p2f.transform!(tr)
    vecn=p2f-p1
    tr=Geom::Transformation.rotation(p1,vecn,ang3d)
    gp.transform!(tr)### rotate to suit in 3D
  end#if
 end#if
 ### make it rotated to suit any edge's face
    if @edge.faces[0]
      gface=nil;gents.each{|e|
        if e.class==Sketchup::Face
          gface=e; break
        end#if
      }
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      camera=model.active_view.camera
      eye=camera.eye
      target=camera.target
      vecc=eye-target ### reversed towards camera
      fface=@edge.faces[0]
      fangle=180.degrees ### worst case...
      @edge.faces.each{|face|
        fface=face if face.normal.angle_between(vecc)<fangle
        fangle=face.normal.angle_between(vecc)
      }
      fnormal=fface.normal
      ang=fnormal.angle_between(gnormal)
      vec=@p2-@p1
      tr=Geom::Transformation.rotation(@p1,vec,ang)
      gp.transform!(tr)
      gnormal=gface.normal
      gnormal.transform!(gp.transformation)
      if gnormal != fnormal
        tr=Geom::Transformation.rotation(@p1,vec,ang*-2)
        gp.transform!(tr)
      end#if
      ### now shift onto the face IF it's not a conormal faced edge
      conormal=false
      if fface and @edge.faces[1]
        (@edge.faces-[fface]).each{|face|
          if face.normal==fnormal or face.normal.reverse==fnormal
            conormal=true;break
          end#if
        }
      end#if
      if not conormal ###if it's true we leave the styled-line centered
        ### find side of edge face is on...
        p1=@edge.start.position;p2=@edge.end.position
        pc=p1.clone;vec=p2-p1
        pc.offset!(vec,(p1.distance(p2))/2)
        pcc=pc.clone;vecc=vec.clone
        tr=Geom::Transformation.rotation(pc,fface.normal,90.degrees)
        vecc.transform!(tr);pcc.offset!(vecc,1.mm)
        vecc.reverse! if fface.classify_point(pcc)!=1
        p11=p1.clone;p11.offset!(vecc,@wid/2)
        gptrans=gp.transformation.to_a
        gptrans[12]=p11.x;gptrans[13]=p11.y;gptrans[14]=p11.z
        gp.transformation=gptrans
      end#if
    end#if
 ### end 3D .....................................................
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    @edge.layer=@hidnlayer if @edge
    ### ###
  end#if style
  return gp
end#def


################################################################################
def LinestyleTool2D::context_dialog()
	model=Sketchup.active_model
	if model.options["UnitsOptions"]["LengthUnit"]<=1 ### imperial = inches
		@width=model.get_attribute("2DLinestyle","width","1.0")
	else ### it's mm
		@width=model.get_attribute("2DLinestyle","width","25")
	end#if
	@style=model.get_attribute("2DLinestyle","style",(db("Continuous_____")))
	###puts @style ##################
	@styleIN=@style
	@color=model.get_attribute("2DLinestyle","color","Black")
	### check if existing custom styles
	@customstyles=model.get_attribute("2DLinestyle","customstyles",[])
	@customstyles=model.get_attribute("2DLinestyle","customstyles",[])
	customstyles=""
@customstyles.sort.each{|a|customstyles<<"|"<<a[0]<<a[1]}if @customstyles[0]
	###
	Sketchup::set_status_text((db("2D Line Style: Settings...")), SB_PROMPT)
	Sketchup::set_status_text("",SB_VCB_LABEL)
	### settings
	prompts=[(db("Width: ")),(db("Style: ")),(db("Color: "))]
	values=[@width,@style,@color]
	### set to suit units
	if model.options["UnitsOptions"]["LengthUnit"]<=1 ### imperial = inches
		widths="0.05|0.1|0.2|0.25|0.5|0.75|1.0|1.5|2.0|3.0|4.0|5.0|6.0|8.0|9.0|10|12|18|20|24|25|36|48|50|60|72|75|84|96|100|108|120|132|144"
	else ### it's mm
		widths="1|2|4|5|8|10|20|25|30|40|50|60|70|75|80|90|100|125|150|175|200|250|300|400|450|500|600|700|750|800|900|1000|1200|1500|1800|2100|2400|2700|3000|3300|3600"
	end#if
	###
styles=(db("Continuous_____|Dot. . . . . . .|Dashed- - - - -|Hidden-- -- -- --|DashDot- . - . - . -|Center-- - -- - --|Phantom--- -- ---|Divide-- .. -- .. --|< Custom Style >"))+customstyles
	materials=model.materials
colors=[]; materials.each{|m|colors.push(m.display_name)}
colors=colors+(Sketchup::Color.names.sort!)
colors.uniq!; colors=colors.join("|")
### dialog...
	popups=[widths,styles,colors]
	title=(db("2D Line Style Settings"))
	results=inputbox(prompts,values,popups,title)
	if not results
		self.deactivate(nil)
		return nil
	else
		@width,@style,@color=results
		###
		model.set_attribute("2DLinestyle","width",@width)
		model.set_attribute("2DLinestyle","color",@color)
		if @style==(db("< Custom Style >"))
			@style=@styleIN
			model.set_attribute("2DLinestyle","style",@styleIN)
			self.custom_dialog()
			return nil
		end#if
		model.set_attribute("2DLinestyle","style",@style)
		###
		tools=model.tools
		tol=tools.pop_tool
		tools.push_tool(tol)
		###
	end#if
end

def LinestyleTool2D::edit()
  def LinestyleTool2D::sdialog()
    model=Sketchup.active_model
    selectedGroup=model.selection[0]
    if model.options["UnitsOptions"]["LengthUnit"]<=1 ### imperial = inches
      @width=selectedGroup.get_attribute("2DLinestyle","width","1.0")
    else ### it's mm
      @width=selectedGroup.get_attribute("2DLinestyle","width","25")
    end#if
    @style=selectedGroup.get_attribute("2DLinestyle","style",(db("Continuous_____")))
    ###puts @style ##################
    @styleIN=@style
    @color=selectedGroup.get_attribute("2DLinestyle","color","Black")
    @len=selectedGroup.get_attribute("2DLinestyle","length","1.0")
    ### check if existing custom styles
    @customstyles=model.get_attribute("2DLinestyle","customstyles",[])
    customstyles=""
	@customstyles.sort.each{|a|customstyles<<"|"<<a[0]<<a[1]}if @customstyles[0]
    ###
    ### settings
    prompts=[(db("Width: ")),(db("Style: ")),(db("Color: "))]
    values=[@width,@style,@color]
    if model.options["UnitsOptions"]["LengthUnit"]<=1 ### imperial = inches
      widths="0.05|0.1|0.2|0.25|0.5|0.75|1.0|1.5|2.0|3.0|4.0|5.0|6.0|8.0|9.0|10|12|18|20|24|25|36|48|50|60|72|75|84|96|100|108|120|132|144"
    else ### it's mm
      widths="1|2|4|5|8|10|20|25|30|40|50|60|70|75|80|90|100|125|150|175|200|250|300|400|450|500|600|700|750|800|900|1000|1200|1500|1800|2100|2400|2700|3000|3300|3600"
    end#if
	styles=(db("Continuous_____|Dot. . . . . . .|Dashed- - - - -|Hidden-- -- -- --|DashDot- . - . - . -|Center-- - -- - --|Phantom--- -- ---|Divide-- .. -- .. --|< Custom Style >"))+customstyles
    materials=model.materials
	colors=[]; materials.each{|m|colors.push(m.display_name)}
	colors=colors+(Sketchup::Color.names.sort!)
	colors.uniq!; colors=colors.join("|")
	### dialog...
    popups=[widths,styles,colors]
    title=db("Edit 2D Line Style Settings")
    results=inputbox(prompts,values,popups,title)
    return nil if not results
    @width,@style,@color=results
    if @style==(db("< Custom Style >"))
        @style=@styleIN
        model.set_attribute("2DLinestyle","style",@styleIN)
        LinestyleTool2D::scustom_dialog()
        return nil
    end#if
    return true
  end#sdialog
  ###
 def LinestyleTool2D::scustom_dialog()
  model=Sketchup.active_model
  Sketchup::set_status_text((db("2D Line Style: Custom Line Style...")), SB_PROMPT)
  Sketchup::set_status_text("",SB_VCB_LABEL)
  ### settings
  prompts=[(db("Style Name: ")),(db("Style Pattern: "))]
  name=(db("MyStyle"))
  pattern="..    ..   "
  values=[name,pattern]
  popups=["",""]
  title=(db("2D Line Style Custom Line Style"))
  results=inputbox(prompts,values,popups,title)
  if not results
    model.set_attribute("2DLinestyle","style",@styleIN)
    @style=@styleIN
    LinestyleTool2D::sdialog()
    return nil
  else
    name,pattern=results
    name=name.tr("~","").tr("|","") ### strip any ~| from new name
    name=name+"~" ### e.g MyLineStyle~ + ... . etc
    customstyles=model.get_attribute("2DLinestyle","customstyles",[])
    names=[];customstyles.sort.each{|a|names<<a[0]}
    ### check pattern is dot+gap otherwise
    badpattern=false
    pattern.split("").each{|e|
      if e !=" " and e !="." or (pattern.split("")[0] !="." or pattern.split("")[-1] !=" ") 
        badpattern=true
        break
      end#if
    }
    if badpattern
      UI.messagebox("'"+pattern+"'\n\n"+(db("Pattern must be only dots and spaces (. )"))+"\n"+(db("and start with a dot and end with a space !"))+"\n\n\n"+"\n\n\n")
      LinestyleTool2D::scustom_dialog()
      return nil
    end#if
    if pattern=="" ### the patterned is to be deleted
      UI.messagebox((db("Custom Line Style '"))+name+"'\n\n"+(db("has been removed from the list.")))
      tstyles=customstyles
      0.upto(customstyles.length-1)do |i|
        tstyles[i]=nil if tstyles[i][0]==name
      end#do
      customstyles=tstyles.compact!
      model.set_attribute("2DLinestyle","customstyles",customstyles)  
      model.set_attribute("2DLinestyle","style",@styleIN)
      LinestyleTool2D::sdialog()
      return nil
    elsif name==(db("< Custom Style >")) ### foolproofing !!!
      UI.messagebox((db("Custom Line Style cannot be named '< Custom Style >'"))+"\n\n"+(db("try again.")))
      LinestyleTool2D::scustom_dialog()
      return nil
    elsif names.include?(name)
      if UI.messagebox(name+"\n'"+pattern+"'\n\n"+(db("exists !"))+"\n\n"+(db("Overwrite it ?"))+"\n\n",MB_YESNO,"")==6
        ### 6=YES 7=NO
        tstyles=[]
        0.upto(customstyles.length-1)do |i|
          if customstyles[i][0]==name
            tstyles<<[name,pattern] ### omits old name,patt version
          else
            tstyles<<i ### adds all others back in
          end#if
        end#do
        customstyles=tstyles
        model.set_attribute("2DLinestyle","customstyles",customstyles)
      else
        LinestyleTool2D::scustom_dialog()
        return nil
      end#if
    else ### new name
      customstyles<<[name,pattern]
      model.set_attribute("2DLinestyle","customstyles",customstyles)
    end#if
    ### reset and go back to where we were
    @style=name+pattern
    model.set_attribute("2DLinestyle","style",@style)
    LinestyleTool2D::sdialog()
    return nil
    ###
  end#if
  ###
 end#scustom_dialog
  ###
  return nil if not LinestyleTool2D::sdialog()
    ### make layers if not existing
  model=Sketchup.active_model
  layers=model.layers
  layernames=[]
  layers.each{|lay|layernames<<lay.name}
  if not layernames.include?("~2D-LINE-HIDN")
    @hidnlayer=layers.add("~2D-LINE-HIDN")
    pb=@hidnlayer.page_behavior=LAYER_IS_HIDDEN_ON_NEW_PAGES
    layers.each{|lay|@hidnlayer=lay if lay.name=="~2D-LINE-HIDN"}
    if model.pages.selected_page
      model.pages.selected_page.set_visibility(@hidnlayer,false)
    end#if
    @hidnlayer.visible=false
  else
    layers.each{|lay|@hidnlayer=lay if lay.name=="~2D-LINE-HIDN"}
    if model.pages.selected_page
      model.pages.selected_page.set_visibility(@hidnlayer,false)
    end#if
    @hidnlayer.visible=false
  end#if
  if not layernames.include?("~2D-LINE-STYL")
    @stylelayer=layers.add("~2D-LINE-STYL")
    pb=@stylelayer.page_behavior=LAYER_IS_VISIBLE_ON_NEW_PAGES
    model.pages.each{|p|p.set_visibility(@stylelayer,true)}
    if model.pages.selected_page
      model.pages.selected_page.set_visibility(@stylelayer,true)
    end#if
    @stylelayer.visible=true
  else
    layers.each{|lay|@stylelayer=lay if lay.name=="~2D-LINE-STYL"}
    if model.pages.selected_page
      model.pages.selected_page.set_visibility(@stylelayer,true)
    end#if
    @stylelayer.visible=true
  end#if
  ###
 def LinestyleTool2D::edit_group()
  model=Sketchup.active_model
  ents=model.active_entities ###
  ### v4.4 >>>
  if model.options["UnitsOptions"]["LengthUnit"]<=1 ### imperial = inches
      @wid=@width.to_f ### in inches
    else ### in mm
      @wid=(@width+"mm").to_l.to_f
    end#if
  ### <<< v4.4
  if /~/=~@style ### it's a custom style
    pattern=@style.split("~")[1] ### MyLineStyle~... .. . etc
    count=pattern.split("").length
    len=@len
    dot_len1=len/((len/@wid).floor)
    patt_len=dot_len1*count
    num_patts=((len)/patt_len).ceil
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    lrun=0.inch
    num_patts.times do |this|
      pattern.split("").each{|e|
        if e=="."
          tr=Geom::Transformation.new(p0)
          inst=gents.add_instance(@compo,tr)
          tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
          inst.transform!(tr)
        end#if
        p0.offset!([1,0,0],dot_len1)
        lrun=lrun+dot_len1
        break if lrun >= len-dot_len1
      }
      break if lrun >= len-dot_len1
    end#times
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ###
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    ###
  elsif @style==(db("Continuous_____")) ###############################
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    tr=Geom::Transformation.new(p0)
    inst=gents.add_instance(@compo,tr)
    ### scale
    tr=Geom::Transformation.scaling(p0,@len,@wid,1)
    inst.transform!(tr)
    ### explode instance
    gents.to_a.each{|e|e.explode}
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    ###
  elsif @style==(db("Dot. . . . . . .")) ### group sets of 1dot+1gap
    ### adjust spacing of dots to suit line length
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*1
    patt_len=dot_len1+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if num_patts>0 and gap_len<@wid/8
      num_patts -=1
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if (dot_len1+(@wid/8)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    (1+num_patts).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(gap_len+dot_len1))
    end#times
=begin
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
=end
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ###
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    ###
  elsif @style==(db("Dashed- - - - -")) ### group sets of 2dot+1gap
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*2
    patt_len=dot_len1+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if num_patts>0 and gap_len<@wid/8
      num_patts -=1
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if (dot_len1+(@wid/8)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    (1+num_patts).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(gap_len+dot_len1))
    end#times
=begin
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
=end
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ###
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    ###
  elsif @style==(db("Hidden-- -- -- --")) ### group sets of 4dot+1gap
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*4
    patt_len=dot_len1+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if num_patts>0 and gap_len<@wid/10
      num_patts -=1
      dots_len=dot_len1*num_patts
      gaps_len=len-dots_len
      gap_len=gaps_len/num_patts
    end#if
    if (dot_len1+(@wid/10)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    (1+num_patts).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(gap_len+dot_len1))
    end#times
=begin
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
=end
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ###
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    ###
  elsif @style==(db("DashDot- . - . - . -")) ### group sets of 2dot+1gap+1dot+1gap
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*2
    dot_len2=@wid*1
    patt_len=dot_len1+@wid+dot_len2+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if num_patts>0 and gap_len<@wid/10
      num_patts -=1
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if (dot_len1+(@wid/10)+dot_len2+(@wid/10)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    dash=true
    (2*(num_patts)).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      if dash
        dot_lenx=dot_len1
        dash=false
      else ### it's a dot
        dot_lenx=dot_len2
        dash=true
      end#if
      tr=Geom::Transformation.scaling(p0,dot_lenx,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(dot_lenx+gap_len))
    end#times
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ###
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    ###
  elsif @style==(db("Center-- - -- - --")) ### group sets of 4dot+1gap+2dot+1gap
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*4
    dot_len2=@wid*2
    patt_len=dot_len1+@wid+dot_len2+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if num_patts>0 and gap_len<@wid/10
      num_patts -=1
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if (dot_len1+(@wid/10)+dot_len2+(@wid/10)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    dash=true
    (2*(num_patts)).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      if dash
        dot_lenx=dot_len1
        dash=false
      else ### it's a dot
        dot_lenx=dot_len2
        dash=true
      end#if
      tr=Geom::Transformation.scaling(p0,dot_lenx,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(dot_lenx+gap_len))
    end#times
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ###
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    ###
  elsif @style==(db("Phantom--- -- ---")) ### group sets of 6dot+1gap+4dot+1gap
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*6
    dot_len2=@wid*4
    patt_len=dot_len1+@wid+dot_len2+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if num_patts>0 and gap_len<@wid/10
      num_patts -=1
      dots_len=(dot_len1+dot_len2)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/2 ###################
    end#if
    if (dot_len1+(@wid/10)+dot_len2+(@wid/10)+dot_len1)>@len
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    dash=true
    (2*(num_patts)).times do |this|
      tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      if dash
        dot_lenx=dot_len1
        dash=false
      else ### it's a dot
        dot_lenx=dot_len2
        dash=true
      end#if
      tr=Geom::Transformation.scaling(p0,dot_lenx,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(dot_lenx+gap_len))
    end#times
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ###
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
    ###
  elsif @style==(db("Divide-- .. -- .. --")) ### group sets of 4dot+1gap+1dot+1gap+1dot+1gap
    ### adjust spacing of dots to suit line length
    dot_len1=@wid*4
    dot_len2=@wid*1
    dot_len3=@wid*1
    patt_len=dot_len1+@wid+dot_len2+@wid+dot_len3+@wid
    len=@len-dot_len1
    num_patts=(len/patt_len).ceil
    if num_patts<=0
      dot_len1=@len
      gap_len=0
      num_patts=0
    else
      dots_len=(dot_len1+dot_len2+dot_len3)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/3 ################### 3 gaps ###
    end#if
    if num_patts>0 and gap_len<@wid/10
      num_patts -=1
      dots_len=(dot_len1+dot_len2+dot_len3)*num_patts
      gaps_len=len-dots_len
      gap_len=(gaps_len/num_patts)/3 ################### 3 gaps ###
    end#if
    if (dot_len1+(@wid/10)+dot_len2+(@wid/10)+dot_len1)>@len ###
      dot_len1=@len
      num_patts=0
    end#if
    gp=ents.add_group()
    gents=gp.entities
    p0=[0,0,0]
    dash=true
    dot=false
    (3*(num_patts)).times do |this|
    tr=Geom::Transformation.new(p0)
      inst=gents.add_instance(@compo,tr)
      if dash
        dot_lenx=dot_len1
        dash=false
        dot=true
      else ### its a dot
        if dot
          dot_lenx=dot_len2
          dot=false
        else
          dot_lenx=dot_len3
          dash=true
          dot=false
        end#if
      end#if
      tr=Geom::Transformation.scaling(p0,dot_lenx,@wid,1)
      inst.transform!(tr)
      p0.offset!([1,0,0],(dot_lenx+gap_len))
    end#times
    if num_patts>0 ### add final dot
      tr=Geom::Transformation.new([len,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling(p0,dot_len1,@wid,1)
      inst.transform!(tr)
    end#if
    ### trap for no face
    if not gents[0]
      tr=Geom::Transformation.new([0,0,0])
      inst=gents.add_instance(@compo,tr)
      tr=Geom::Transformation.scaling([0,0,0],@len,@wid,1)
      inst.transform!(tr)
    end#if
    ### explode contents = all instances
    gents.to_a.each{|e|e.explode}
    ###
    suffx="-"+@width+"-"+@style.gsub(/[^A-Za-z0-9]/,'')+"-"+@color+"-"+@len.to_s; gp.name="~2D~STYLED_LINE"+suffx
    gents.each{|e|
      if e.class==Sketchup::Face
        e.material=@color
        e.back_material=@color
      end#if
      e.hidden=true if e.class==Sketchup::Edge
      e.casts_shadows=false
      e.receives_shadows=false
    }
    gp.casts_shadows=false
    gp.receives_shadows=false
    gp.set_attribute("2DLinestyle","width",@width)
    gp.set_attribute("2DLinestyle","style",@style)
    gp.set_attribute("2DLinestyle","color",@color)
    gp.set_attribute("2DLinestyle","length",@len)
    gp.layer=@stylelayer
  end#if style
  return gp
 end#def edit_group
  ###
  ### ##################################################################
  model=Sketchup.active_model
  ss=model.selection
  model.start_operation(db("Edit 2D Line Style"))
  ### make face group/compo dot
  @compo=LinestyleTool2D.make_dot("~2D~DOT")
  ### now have '@compo' building block dot for lines
  ###
  gps=[];ss.each{|e|gps<<e if e.class==Sketchup::Group and e.get_attribute("2DLinestyle","width",false)}
  gps2go=[];tedge=nil;@edge=nil;@trans=nil
  gps.each{|g|
    @len=g.get_attribute("2DLinestyle","length",false)
    @wid=@width.to_f ### inches ?
    @trans=g.transformation
    ### .to_a ### strip out scaling stuff ?
    ### scalex=Math.sqrt(@trans[0]**2+@trans[1]**2+@trans[2]**2)
    tedge=model.active_entities.add_group()########### v4.0
    @edge=tedge.entities.add_line([0,0,0],[0,0,@len])########
    if @len
      gp=LinestyleTool2D::edit_group()
      gp.transformation=@trans
      gp.layer=g.layer
      gps2go<<g
    end#if @len
    gps2go<<tedge
  }### end gps
  gps2go.each{|g|g.erase! if g.valid?}
  model.commit_operation
  ###
end#edit


def LinestyleTool2D::ok
  if Sketchup.active_model.selection[0] and Sketchup.active_model.selection[0].class==Sketchup::Group and Sketchup.active_model.selection[0].get_attribute("2DLinestyle","width",false)
    return true
  else
    return false
  end#if
end#

end # class

end#mod
#-----------------------------------------------------------------------------
# shortcut
#def linestyletool2D
    #Sketchup.active_model.select_tool LinestyleTool2D.new
#end
######-----------------------------------------------

