###-------------------------------------------------------------------------------- # Name : TubeAlongPath # # Description : Creates circular faced 'followme' tube extrusions along a path - # Use it to make pipes, ducts, rails etc, # starting from a selection of joined edges # # Author : TIG (c) 7/2005 # based on an original wall making idea by Didier Bur # and using some vertex array ideas from Rick Wilson # # Usage : Select joined lines, arcs, circles, curves, etc. # Select "Tube Along Path" from the Plugins menu. # In dialog choose Circle or Polygon, enter radius, number of segements and OK. # # The extrusion is made*. # *The extrusion is grouped so it does not interact with adjacent surfaces - # afterwards just explode it if appropriate. # # The selected path remains highlighted after the extrusion is made - # you can use this to move or delete unwanted central paths etc # The path stays selected even after an undo. # Any curves in the path become separate segments on edge etc. # # A Circle has smoothed edges to faces but a Polygon shows all edges as lines. # The default for segments is 12, the minimum is 3. # # The alignment is always 'Centroid' [along circle's centre line], # # The radius is always measured square to the vector of the first path's line. # A radius that is less than the length of pieces of path edge might # give correct but unexpected extrusions, which might need manually tidying... # Closed loop paths are fully extruded, but might need manually tidying. # Multiple arc and other complex 3D paths might give unexpected results. # # Radius cannot be zero and will return an error. # A branching path returns just the lone starting face - i.e gives an error. # Selected edges that are not joined (i.e. common end-starts) will not be # extruded - only the first edge or joined group of edges will extrude. # # # # Type : tool # # Version : 1.0 30/7/5 first release. # 1.1 1/8/5 face forced to avoid followme v5 bug simplified loop. # 1.2 7/8/5 extrusion grouped to avoid rare coincident-face bug-splats, # circle or polygon extrusion added, # number of segments option added. # ###-------------------------------------------------------------------------------- require 'sketchup.rb' ### def tube_along_path model = Sketchup.active_model model.start_operation "tube_along_path" entities = model.active_entities ss = model.selection if ss.empty? UI.messagebox("No Selection.") return nil end ### dialog ### types = ["Circle","Polygon"] enums = [types.join("|")] if not $radiusIn values = ["Circle", 20.mm, 12] else values = [$typeIn, $radiusIn, $segmentsIn] ### 7/8/5 end prompts = ["Circle or Polygon ? : ", "Radius: ", "Number of Segments: "] ### 7/8/5 results = inputbox prompts, values, enums, "Tube Parameters (mm)" ### 7/8/5 return nil if not results ### i.e. the user cancelled the operation $typeIn = results[0] ### 7/8/5 $radiusIn = results[1] ### 7/8/5 $segmentsIn = results[2] ### 7/8/5 radius = $radiusIn if $radiusIn == 0.mm ### can't be 0 ### $radiusIn = 20.mm UI.messagebox("Zero Radius NOT allowed ! ") return nil end segs = $segmentsIn ### 7/8/5 if $segmentsIn < 3 ### can't be 0 ### $segmentsIn = 12 UI.messagebox("Fewer than 3 Faces NOT allowed ! ") return nil end ### 7/8/5 ### this next bit is thanks to Rick Wilson's weld.rb model=Sketchup.active_model ents=model.active_entities sel=model.selection sl=sel.length verts=[] edges=[] newVerts=[] startEdge=startVert=nil #CHECK FOR A VALID SELECTION ### return UI.messagebox("Please select at least 2 edges") if sl < 2 ### WE can do 1 edge... # if sel.first.curve # return UI.messagebox("Please select at least 2 non-joined edges") if sel.length == sel.first.curve.count_edges # end #DELETE NON-EDGES, GET THE VERTICES sel.each {|item| edges.push(item) if item.typename=="Edge"} edges.each {|edge| verts.push(edge.vertices)} verts.flatten! #FIND AN END VERTEX vertsShort=[] vertsLong=[] verts.each do |v| if vertsLong.include?(v) vertsShort.push(v) else vertsLong.push(v) end end if (startVert=(vertsLong-vertsShort).first)==nil startVert=vertsLong.first closed=true startEdge = startVert.edges.first else closed=false startEdge = (edges & startVert.edges).first end sel.clear #SORT VERTICES, LIMITING TO THOSE IN THE SELECTION SET if startVert==startEdge.start newVerts=[startVert] counter=0 while newVerts.length < verts.length edges.each do |edge| if edge.end==newVerts.last newVerts.push(edge.start) elsif edge.start==newVerts.last newVerts.push(edge.end) end end counter+=1 if counter > verts.length return nil if UI.messagebox("There seems to be a problem. Try again?", MB_YESNO)!=6 newVerts.reverse! reversed=true end end else newVerts=[startVert] counter=0 while newVerts.length < verts.length edges.each do |edge| if edge.end==newVerts.last newVerts.push(edge.start) elsif edge.start==newVerts.last newVerts.push(edge.end) end end counter+=1 if counter > verts.length return nil if UI.messagebox("There seems to be a problem. Try again?", MB_YESNO)!=6 newVerts.reverse! reversed=true end end end ###newVerts.uniq! ### allow IF closed newVerts.reverse! if reversed #CONVERT VERTICES TO POINT3Ds newVerts.collect!{|x| x.position} ###newVerts.push(newVerts[0]) ### now have an array of vertices in order with NO forced closed loop ... ### - do stuff - ### pt1 = newVerts[0] pt2 = newVerts[1] vec = pt1.vector_to pt2 group=entities.add_group ### 7/8/5 entities=group.entities ### 7/8/5 if $typeIn == "Circle" ### 7/8/5 theRim = entities.add_circle pt1, vec, radius, segs else theRim = entities.add_ngon pt1, vec, radius, segs end ### 7/8/5 theFace = entities.add_face theRim ### 7/8/5 if pt1.x == pt2.x and pt1.y == pt2.y and pt1.z < pt2.z ### flip so not inside out ! ### 7/8/5 theFace.reverse! end @@theEdges= [] 0.upto(newVerts.length-2) do |i| @@theEdges[i] = ents.add_line(newVerts[i],newVerts[i+1]) ### make vertices into edges end ### follow me along selected edges theExtrusion=theFace.reverse!.followme @@theEdges ### ### if not theExtrusion UI.messagebox("The selected Path branches ! \nCannot extrude the Tube ! \nRe-select a single continuous path... ") entities.erase_entities theRim end ### model.commit_operation ### restore selection set of edges and display them theEdgeX = [] 0.upto(newVerts.length-2) do |i| theEdgeX[i] = ents.add_line(newVerts[i],newVerts[i+1]) ### make vertices into edges end model.selection.clear model.selection.add theEdgeX end ### end def ### menu bits if( not file_loaded?("TubeAlongPath.rb") )### UI.menu("Plugins").add_separator UI.menu("Plugins").add_item("Tube Along Path") { tube_along_path } end ### file_loaded("TubeAlongPath.rb")### ###-----------------------------------------------------------------------------