hope TIG is ok with it:
main 2 routines:
@@dist=nil
def initialize(dist=nil)
@toolname="extrudeEdgesByOffset"
if dist==0
puts 'Extrude Edges by Offset' + '; Offset cannot be 0.'
return nil
end#if
model=Sketchup.active_model
ss=model.selection
edges=[]
ss.each{|e|edges << e if e.class==Sketchup;;Edge}
if not edges[1]
if not dist
UI.messagebox('Extrude Edges by Offset') + ('; Must Select >=2 Edges.')
else
puts 'Extrude Edges by Offset' + '; Must Select >=2 Edges.'
end
return nil
end#if
verts=[]
edges.each{|e| verts << e.vertices}
verts.flatten!
verts.uniq!
pts=[]
verts.each{|v| pts << v.position}
cop=true
vec=Geom;;Vector3d.new(0,0,0)
edges[0..-2].each_with_index{|e,i| vec=e.line[1].cross(edges[i+1].line[1])}
vec=Z_AXIS.clone if vec.length==0 ### all in line
plane=[pts[0],vec]
pts.each{|p|
if not p.on_plane?(plane)
cop=false
break
end
}
if not dist
if not cop
UI.messagebox('Extrude Edges by Offset') + ('; Edges must be coplanar.')
return nil
end
@@dist=0.to_l if not @@dist
Sketchup;;set_status_text(("Extrude Edges by Offset")+"; "+("Distance; "), SB_PROMPT)
results=inputbox(["Distance; "],[@@dist],"Extrude Edges by Offset"+"...")
return nil if not results
if results[0]==0
UI.messagebox('Extrude Edges by Offset'+'; Offset cannot be 0!'+"\n"+"Try again"+"...")
results=inputbox(["Distance; "],[@@dist],"Extrude Edges by Offset"+"...")
return nil if not results or results[0]==0
end#if
@@dist=results[0]
else ### dist passed as arg
if not cop
puts 'Extrude Edge by Offset'+'; Edges must be coplanar.'
return nil
end
@@dist=dist.to_l
end#if
###
model.start_operation("Extrude Edges by Offset"+' '+@@dist.to_s)
dist=@@dist
group=model.active_entities.add_group()
ents=group.entities
###
if edges.length==verts.length ### looped
###
tface=ents.add_face(pts)
###
fverts=tface.outer_loop.vertices
fpts=[]
0.upto(fverts.length-1) do |a|
vec1=(fverts[a].position-fverts[a-(fverts.length-1)].position).normalize
vec2=(fverts[a].position-fverts[a-1].position).normalize
vec3=(vec1+vec2).normalize
if vec3.valid?
ang=vec1.angle_between(vec2)/2
ang=180.degrees if vec1.parallel?(vec2)
vec3.length=dist/Math;;sin(ang)
t=Geom;;Transformation.new(vec3)
if fpts.length > 0
if not (vec2.parallel?(fpts.last.vector_to(fverts[a].position.transform(t))))
t=Geom;;Transformation.new(vec3.reverse)
end
end
fpts << fverts[a].position.transform(t)
end
end
nface=ents.add_face(fpts)
tface.erase! if tface.valid? and dist>0
nface.erase! if nface.valid? and dist<0
face=nil; ents.each{|e|face=e if e.class==Sketchup;;Face}
face.reverse! if face.normal.z<0
ol=face.outer_loop
verts=ol.vertices if dist<0
il=(face.loops-[ol])[0]
verts=il.vertices if dist>0
verts.each_with_index{|vert,a|
vec1=(verts[a].position.vector_to(verts[a-(verts.length-1)].position)).normalize
vec2=(verts[a].position.vector_to(verts[a-1].position)).normalize
vec3=(vec1+vec2).normalize
if vec3.valid?
ang=vec1.angle_between(vec2)/2
ang=90.degrees if vec1.parallel?(vec2)
vec3.length= -dist/Math;;sin(ang)
t=Geom;;Transformation.new(vec3)
p=verts[a].position
pt=p.transform(t)
ents.add_line(p,pt)
end
}
###
tr=Geom;;Transformation.new()
len=ents.length
len.times{ents.intersect_with(true, tr, ents, tr, true, ents.to_a)}
###
cedges=[]; ents.each{|e|cedges << e if e.class==Sketchup;;Edge}
###
else ### open ended
###
edges.each{|e|ents.add_line(e.start.position, e.end.position)}
edges=ents.to_a
es=[]
ee=[]
se=[]
edges.each{|e|
if not e.start.edges[1]
es=e.start
ee=e.end
se=e
break
elsif not e.end.edges[1]
es=e.end
ee=e.start
se=e
break
end#if
}
nedges=[se]
verts=[es,ee]
(edges.length-1).times{
edges.each{|e|
next if nedges.include?(e)
if e.start==ee
verts << e.vertices
ee=e.end
nedges << e
elsif e.end==ee
verts << e.vertices
ee=e.start
nedges << e
end
}
}
verts.flatten!
verts.uniq!
###
opts=[]
verts.each_with_index{|vert,a|
if a==0 #special case for start vertex
v=verts[a].position.vector_to(verts[a+1].position).normalize
f=dist/dist.abs
t=Geom;;Transformation.rotation(verts[0].position, vec, 90.degrees*f)
vec3=v.transform(t)
vec3.length=dist.abs
opts << verts[a].position.transform(vec3)
elsif a==verts.length-1 #special case for end vertex
v=verts[a-1].position.vector_to(verts[a].position).normalize
f=dist/dist.abs
t=Geom;;Transformation.rotation(verts[a].position, vec, 90.degrees*f)
vec3=v.transform(t)
vec3.length=dist.abs
opts << verts[a].position.transform(vec3)
else
vec1=(verts[a].position.vector_to(verts[a+1].position)).normalize
vec2=(verts[a].position.vector_to(verts[a-1].position)).normalize
vec3=(vec1+vec2).normalize
if vec3.valid?
ang=vec1.angle_between(vec2)/2
ang=90.degrees if vec1.parallel?(vec2)
vec3.length=dist/Math;;sin(ang)
t=Geom;;Transformation.new(vec3)
if not vec2.parallel?(opts[-1].vector_to(verts[a].position.transform(t)))
t=Geom;;Transformation.new(vec3.reverse)
end
opts << verts[a].position.transform(t)
end
end#if
}
begin
nedges=ents.add_edges(opts)
rescue
nedges=[]
end
pts=[]
verts.each{|v|pts << v.position}
ents.erase_entities(edges)
begin
edges=ents.add_edges(pts)
rescue
edges=[]
end
pts.each_with_index{|p,i|ents.add_line(pts[i],opts[i])}
###
tr=Geom;;Transformation.new()
len=ents.length
len.times{ents.intersect_with(true, tr, ents, tr, true, ents.to_a)}
###
cedges=[]; ents.each{|e|cedges << e if e.class==Sketchup;;Edge}
cedges.length.times{
ents.to_a.each{|e|
next if e.class!=Sketchup;;Edge or not e.valid?
e.find_faces
}
}
ents.to_a.each{|e|e.reverse! if e.class==Sketchup;;Face and e.normal.z<0}
###
end#if
###
model.commit_operation
# CREATE REVERSE GROUP
model.start_operation("Extrude Edges by Offset - Reverse Side"+' '+@@dist.to_s)
dist=@@dist*-1
group=model.active_entities.add_group()
ents=group.entities
###
if edges.length==verts.length ### looped
###
tface=ents.add_face(pts)
###
fverts=tface.outer_loop.vertices
fpts=[]
0.upto(fverts.length-1) do |a|
vec1=(fverts[a].position-fverts[a-(fverts.length-1)].position).normalize
vec2=(fverts[a].position-fverts[a-1].position).normalize
vec3=(vec1+vec2).normalize
if vec3.valid?
ang=vec1.angle_between(vec2)/2
ang=180.degrees if vec1.parallel?(vec2)
vec3.length=dist/Math;;sin(ang)
t=Geom;;Transformation.new(vec3)
if fpts.length > 0
if not (vec2.parallel?(fpts.last.vector_to(fverts[a].position.transform(t))))
t=Geom;;Transformation.new(vec3.reverse)
end
end
fpts << fverts[a].position.transform(t)
end
end
nface=ents.add_face(fpts)
tface.erase! if tface.valid? and dist>0
nface.erase! if nface.valid? and dist<0
face=nil; ents.each{|e|face=e if e.class==Sketchup;;Face}
face.reverse! if face.normal.z<0
ol=face.outer_loop
verts=ol.vertices if dist<0
il=(face.loops-[ol])[0]
verts=il.vertices if dist>0
verts.each_with_index{|vert,a|
vec1=(verts[a].position.vector_to(verts[a-(verts.length-1)].position)).normalize
vec2=(verts[a].position.vector_to(verts[a-1].position)).normalize
vec3=(vec1+vec2).normalize
if vec3.valid?
ang=vec1.angle_between(vec2)/2
ang=90.degrees if vec1.parallel?(vec2)
vec3.length= -dist/Math;;sin(ang)
t=Geom;;Transformation.new(vec3)
p=verts[a].position
pt=p.transform(t)
ents.add_line(p,pt)
end
}
###
tr=Geom;;Transformation.new()
len=ents.length
len.times{ents.intersect_with(true, tr, ents, tr, true, ents.to_a)}
###
cedges=[]; ents.each{|e|cedges << e if e.class==Sketchup;;Edge}
###
else ### open ended
###
edges.each{|e|ents.add_line(e.start.position, e.end.position)}
edges=ents.to_a
es=[]
ee=[]
se=[]
edges.each{|e|
if not e.start.edges[1]
es=e.start
ee=e.end
se=e
break
elsif not e.end.edges[1]
es=e.end
ee=e.start
se=e
break
end#if
}
nedges=[se]
verts=[es,ee]
(edges.length-1).times{
edges.each{|e|
next if nedges.include?(e)
if e.start==ee
verts << e.vertices
ee=e.end
nedges << e
elsif e.end==ee
verts << e.vertices
ee=e.start
nedges << e
end
}
}
verts.flatten!
verts.uniq!
###
opts=[]
verts.each_with_index{|vert,a|
if a==0 #special case for start vertex
v=verts[a].position.vector_to(verts[a+1].position).normalize
f=dist/dist.abs
t=Geom;;Transformation.rotation(verts[0].position, vec, 90.degrees*f)
vec3=v.transform(t)
vec3.length=dist.abs
opts << verts[a].position.transform(vec3)
elsif a==verts.length-1 #special case for end vertex
v=verts[a-1].position.vector_to(verts[a].position).normalize
f=dist/dist.abs
t=Geom;;Transformation.rotation(verts[a].position, vec, 90.degrees*f)
vec3=v.transform(t)
vec3.length=dist.abs
opts << verts[a].position.transform(vec3)
else
vec1=(verts[a].position.vector_to(verts[a+1].position)).normalize
vec2=(verts[a].position.vector_to(verts[a-1].position)).normalize
vec3=(vec1+vec2).normalize
if vec3.valid?
ang=vec1.angle_between(vec2)/2
ang=90.degrees if vec1.parallel?(vec2)
vec3.length=dist/Math;;sin(ang)
t=Geom;;Transformation.new(vec3)
if not vec2.parallel?(opts[-1].vector_to(verts[a].position.transform(t)))
t=Geom;;Transformation.new(vec3.reverse)
end
opts << verts[a].position.transform(t)
end
end#if
}
begin
nedges=ents.add_edges(opts)
rescue
nedges=[]
end
pts=[]
verts.each{|v|pts << v.position}
ents.erase_entities(edges)
begin
edges=ents.add_edges(pts)
rescue
edges=[]
end
pts.each_with_index{|p,i|ents.add_line(pts[i],opts[i])}
###
tr=Geom;;Transformation.new()
len=ents.length
len.times{ents.intersect_with(true, tr, ents, tr, true, ents.to_a)}
###
cedges=[]; ents.each{|e|cedges << e if e.class==Sketchup;;Edge}
cedges.length.times{
ents.to_a.each{|e|
next if e.class!=Sketchup;;Edge or not e.valid?
e.find_faces
}
}
ents.to_a.each{|e|e.reverse! if e.class==Sketchup;;Face and e.normal.z<0}
###
end#if
###
model.commit_operation
Sketchup.send_action("selectSelectionTool;")
end#def