diff --git a/TEST_CAIXIA b/TEST_CAIXIA new file mode 100644 index 0000000..0e90344 --- /dev/null +++ b/TEST_CAIXIA @@ -0,0 +1,891 @@ +=begin + Copyright 2014 (c), TIG + All Rights Reserved. + THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED + WARRANTIES,INCLUDING,WITHOUT LIMITATION,THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +### + extrudeEdgesByFaces.rb +### + Extrudes an 'initial-profile' Face along a 'rail' curve to form a + faced-mesh group, a final 'melding-profile' Face option can control + the mesh's final form. +### +Usage: + Make 1 or two Faces to use as the Profile/Melding-Profile. + The 3D location/orientation of the Faces is important - see below... + Any 'inner loops' [holes] in Faces are ignored. + To make a 'hollow' tube-like extrusion face the two - ring & hole - + extrude separate forms ensuring that the inner in 'inside out', then + merge the groups/intersect and erase the unwanted end 'caps'... + Make a 'curve' (Arcs/Beziers/PolyLines/Welded-Edges etc) to use + as the Rail. + These will represent the 'Initial-Profile-Face', the 'Rail', and the + 'Melding-Profile-Face'. + The 'Initial-Profile-Face' is best sharing a common vertex with the + 'Rail': if not it will be 'relocated' at the Rail's start to suit - + the nearest node on a Face's edges to the Rail will be used as a snap. + You are asked for the 'Melding-Profile-Face': you can pick on + the 'Initial-Profile-Face' again to form a simpler mesh from just + that one Face, but using a 'Melding-Profile-Face' means that all of + the intermediate Profiles will have a proportional 'melding' between + the 'Initial-Profile-Face' and the [Final] 'Melding-Profile-Face' + along the Rail's intermediate nodes... + The location of this 'Melding-Profile-Face' also affects the result, + it is best sharing a common vertex with the 'Rail': if not it will be + 'relocated' at the Rail's end to suit - the nearest node on a Face's + edges to the Rail will be used as a snap. + + Run the Tool from Plugins > 'Extrude Edges by Faces'. + or click on Toolbar 'Extrude Edges by Faces'. + Activate this Toolbar from View > Toolbars if not loaded. + Follow the prompts on the VCB. + Pick the Faces and Rail Curve in the order instructed... + First pick the 'Initial-Profile-Face', then pick the Rail's Curve. + Finally pick a 'Melding-Profile-Face', or you can pick the + 'Initial-Profile-Face' again for a simpler mesh form without a fixed + final-profile-face form etc. + After selecting these faces & curve it auto-runs the mesh-maker... + A grouped triangulated mesh is made based on these faces & curve... + The 'ends' are also 'capped' with faces. + Then there are dialogs asking for Yes/No replies... + If you want to 'reverse' the faces in the mesh. + If you want to erase any 'coplanar edges' in the mesh. + If you want to 'smooth' the edges in the mesh. + You can Undo these steps individually immediately afterwards... + + NOTE: + Multi-segmented edged faces increase processing time exponentially... + the mesh WILL eventually be made, but the screen might 'white out' + and it might appear to stop for several minutes... but it is working... + Profile-Faces with the same number of segments/edges or with + them as simple 'multiples' will produce the fewest facets. + It is sensible to 'match' the segments in profile-faces, + otherwise a mesh can become VERY faceted or possibly uneven - + and also it might take ages to make. + However, using say a 'square' face melding to a 'circular' face will + necessitate auto-divisions to match the circle's segment count. + For example, for two faces' edge-sets their segments for each part of + a rail's curve are dictated by the most segmented set: + 10 + 20 segments=20 x 2 = 40 facets + 10 + 10 segments=10 x 2 = 20 facets + 10 + 7 segments=10 x 2 = 20 facets + 10 + 3 segments=10 x 2 = 20 facets + [ 3 is the minimum edges a face can have ] + The lesser segmented edge-set will always have some of its segments + re-divided to match the more segmented ones segments. This + division is spaced evenly for edge-sets that are segmented as + multiples, but this can only approximate to 'even' otherwise... + + For a rail that is to be 'linear' draw an Edge & Divide it as needed + equivalent to the number of 'facets' required or to match the other + rail, then 'Weld' the pieces together into one 'straight' curve. + If you want a single Edge as a rail then make a single segment + Polyline with BZ Tools, or make a Curve out of two edges [with Weld + etc] and split the Curve with another perpendicular Edge and Erase + this and the unwanted Edge in the Curve - then you have a Curve with + a single Edge - alternatively Divide the Edge into two and get a + seam in the mesh - you can always use a 'Erase-Coplanar-Edges' tool + to minimize the divisions later or you can always add back any lost + triangulation by using the 'Triangulate Quad Faces' tool... + Occasionally Curves made from welded/re-welded/re-re-welded[!]/etc + have vertices in an order that can be unexpectedly convoluted + and create weird results - if you remake the Curve from scratch + it should be OK. Sometimes cutting and pasting-in-place or + grouping and exploding a problem curve can also fix it for use... + +Donations: + Are welcome [by PayPal], please use 'TIGdonations.htm' in the + ../Plugins/TIGtools/ folder. + +Version: + 1.0 20100219 First release. + 1.1 20100220 Color coding of picked faces/curves added. + ProfileFaceEdges=Cyan + Rail=Magenta + MeldingProfileFaceEdges=DarkCyan + 1.2 20100222 Tooltips etc now deBabelized properly. + 1.3 20100330 Rare glitch woth self.xxx fixed. + 1.4 20111023 Smooth now ignores edges with only one face. + 1.5 20111207 Group.copy replaced to avoid clashes with rogue scripts. + 2.0 20130520 Becomes part of ExtrudeTools Extension. + +=end +### +module ExtrudeTools +### +toolname="extrudeEdgesByFaces" +cmd=UI::Command.new(db("Extrude Edges by Faces")){Sketchup.active_model.select_tool(ExtrudeTools::ExtrudeEdgesByFaces.new())} +cmd.tooltip=db("Extrude Edges by Faces") +cmd.status_bar_text="..." +cmd.small_icon=File.join(EXTOOLS, "#{toolname}16x16.png") +cmd.large_icon=File.join(EXTOOLS, "#{toolname}24x24.png") +SUBMENU.add_item(cmd) +TOOLBAR.add_item(cmd) +### +class ExtrudeEdgesByFaces + +include ExtrudeTools + +class Sketchup::Face + def orient_connected_faces + @connected_faces=[] + self.all_connected.each{|e| + if e.class==Sketchup::Face + e.edges.each{|edge| + if edge.faces[1] + @connected_faces << e + break + end#if + } + end#if + } + @connected_faces=[self] + @connected_faces + @connected_faces.uniq! + @awaiting_faces=@connected_faces + @processed_faces=[self] + @done_faces=[] + msg=""#(db("Orienting Faces")) + ### + while @awaiting_faces[0] + msg=msg+"." + @processed_faces.each{|face| + if not @done_faces.include?(face) + Sketchup::set_status_text(msg) + @face=face + face_flip + end#if + } + end#while + Sketchup::set_status_text("") + end#def + def face_flip + @awaiting_faces=@awaiting_faces-[@face] + @face.edges.each{|edge| + rev1=edge.reversed_in?(@face) + @common_faces=edge.faces-[@face] + @common_faces.each{|face| + rev2=edge.reversed_in?(face) + face.reverse! if @awaiting_faces.include?(face) and rev1==rev2 + @awaiting_faces=@awaiting_faces-[face] + @processed_faces< 6 + @model.start_operation((db("Extrude Edges by Faces")),true) + ### 'false' is best to see results as UI/msgboxes... + else + @model.start_operation((db("Extrude Edges by Faces"))) + end + @state=0 ### counter for selecting faces and curves + @profile=nil + @mprofile=nil ###v2.4 typo fix + @profiles=[] + @mprofiles=[] + @profileface=nil + @mprofileface=nil + @rail1=nil + @rail2=nil + @msg=(db("Extrude Edges by Faces: Select the 'Profile' Face...")) + Sketchup::set_status_text(@msg) + end#activate + + def reset + ### + end#reset + + def deactivate(view) + ### view.inactivate if view ### + Sketchup.send_action("selectSelectionTool:") + end#deactivate + +def resume(view) + Sketchup::set_status_text(@msg) + view.invalidate +end + + def onMouseMove(flags,x,y,view) + case @state + when 0 ### getting the profile + #view.invalidate + view.tooltip=(db("Pick Profile Face")) + when 1 ### getting the rail + #view.invalidate + view.tooltip=(db("Pick Rail Curve")) + when 2 ### getting the melding + #view.invalidate + view.tooltip=(db("Pick Melding Profile Face")) + end#case + end#onMouseMove + + def onLButtonDown(flags,x,y,view) + ph=view.pick_helper + ph.do_pick(x,y) + best=ph.best_picked + if best and best.valid? + case @state + when 0 + if best.class==Sketchup::Face + @profileface=best + @profiles=@profileface.outer_loop.edges + @sel.add(@profileface) + @sel.add(@profiles) + @msg=(db("Extrude Edges by Faces: Select the 'Rail' Curve...")) + Sketchup::set_status_text(@msg) + @state=1 + else + UI.beep + view.invalidate + view.tooltip=(db("Pick Profile Face")) + end#if + when 1 + if best.class==Sketchup::Edge and best.curve and not @profiles.include?(best.curve.edges[0]) ### NOT face edge + @sel.add(best.curve.edges) + @rail1=best + @msg=(db("Extrude Edges by Faces: Select the 'Melding-Profile' Face...")) + Sketchup::set_status_text(@msg) + @state=2 + else + UI.beep + view.invalidate + view.tooltip= db("Pick Rail Curve") + end#if + when 2 + if best.class==Sketchup::Face + @mprofileface=best + @mprofiles=@mprofileface.outer_loop.edges + @sel.add(@mprofileface) + @sel.add(@mprofiles) + #view.invalidate + @msg=(db("Extrude Edges by Faces: Making Mesh from Face Profiles and Rail Curve...")) + Sketchup::set_status_text(@msg) + self.make_mesh() + else + UI.beep + view.invalidate + view.tooltip=(db("Pick Melding Profile Face")) + end#if + end#case + end#if + end#onLButtonDown + + def draw(view) + view.line_width=7 + if @profiles + view.drawing_color="cyan" + @profiles.each{|e|view.draw_line(e.start.position,e.end.position)} + end#if + if @rail1 + view.drawing_color="magenta" + @rail1.curve.edges.each{|e|view.draw_line(e.start.position,e.end.position)} + end#if + if @mprofiles + view.drawing_color="darkcyan" + @mprofiles.each{|e|view.draw_line(e.start.position,e.end.position)} + end#if + end#draw + + + def make_mesh() + + @profile_edges=@profiles + @rail1_edges=@rail1.curve.edges + @mprofile_edges=@mprofiles + ### v2... find most segmented rail & profile + if @profile_edges.length >= @mprofile_edges.length + max=@profile_edges.length + min=@mprofile_edges.length + is_p=true + else + max=@mprofile_edges.length + min=@profile_edges.length + is_p=false + end#if + ### work out divisions of other lesser segmented profile edges and the remainder + div=(max/min) ### every min edge gets divided up by this + rem=(max-(div*min)) ### this is how many edges get div+1 divisions + ### work out which edges get extra division ------------------------ + if rem==0 + xdivs=[] + elsif (rem.to_f/min.to_f)==0.5 + xdivs=[];ctr=-1 + (min.to_f/2.0).round.to_i.times{ctr=ctr+2;xdivs<0.5 + xdivs=[] + min.times{|i|;xdivs<points[0].distance(points1[-1]) + points1.reverse! + end#if + ############### + if points[0].distance(points1[0])>points[0].distance(points1[-1]) + points1.reverse! + end#if + ### + ### ensure reversed properly + if @profileface == @mprofileface + if points != pointsm + pointsm.reverse! + end#if + end#if + ### + tpoints1=[] + points1.each{|p|tpoints1< 6 + @model.start_operation((db("Extrude Edges by Faces: Reversing Face ")),true) + ### 'false' is best to see results as UI/msgboxes... + else + @model.start_operation((db("Extrude Edges by Faces: Reversing Face "))) + end + tick=1 + faces.each{|e| + e.reverse! + @msg=((db("Extrude Edges by Faces: Reversing Face "))+tick.to_s+(db(" of "))+faces.length.to_s) + Sketchup::set_status_text(@msg) + tick+=1 + } + @model.commit_operation + end#if + @msg=(db("Extrude Edges by Faces: Erase Coplanar Edges ?")) + Sketchup::set_status_text(@msg) + if UI.messagebox((db("Extrude Edges by Faces:"))+"\n\n"+(db("Erase Coplanar Edges ?"))+"\n\n\n\n",MB_YESNO,"")==6 ### 6=YES 7=NO + ### pause here so we see result... + if Sketchup.version[0,1].to_i > 6 + @model.start_operation((db("Extrude Edges by Faces: Erase Coplanar Edges ?")),true) + ### 'false' is best to see results as UI/msgboxes... + else + @model.start_operation((db("Extrude Edges by Faces: Erase Coplanar Edges ?"))) + end + counter=0 + 4.times do ### to make sure we got all of them ! + gents.to_a.each{|e| + if e.valid? and e.class==Sketchup::Edge + if not e.faces[0] + e.erase! + counter+=1 + @msg=((db("Extrude Edges by Faces: Coplanar Edges Erased= "))+counter.to_s) + Sketchup::set_status_text(@msg) + elsif e.faces.length==2 and e.faces[0].normal.dot(e.faces[1].normal)> 0.99999999999 #### + e.erase! + counter+=1 + @msg=((db("Extrude Edges by Faces: Coplanar Edges Erased= "))+counter.to_s) + Sketchup::set_status_text(@msg) + end#if + end#if + } + end#times + @model.commit_operation + end#if + + + ### intersect with self + @msg=(db("Extrude Edges by Faces: Intersect Mesh with Self ?")) + Sketchup::set_status_text(@msg) + if UI.messagebox((db("Extrude Edges by Faces:"))+"\n\n"+(db("Intersect Mesh with Self ?"))+"\n\n"+(db("This is only necessary with convoluted meshes...")),MB_YESNO,"")==6 ### 6=YES 7=NO + ### pause here so we see result... + if Sketchup.version[0,1].to_i > 6 + @model.start_operation((db("Extrude Edges by Faces: Intersect Mesh with Self ?")),true) + ### 'false' is best to see results as UI/msgboxes... + else + @model.start_operation((db("Extrude Edges by Faces: Intersect Mesh with Self ?"))) + end + @msg=(db("Extrude Edges by Faces: Intersecting Mesh with Self... Please Wait...")) + Sketchup::set_status_text(@msg) + gentsa1=group.entities.to_a + gnum1=gents.length + group.entities.intersect_with(true,group.transformation,group,group.transformation,true,group) + gentsa2=group.entities.to_a + gnum2=gents.length + @model.commit_operation + end#intersect + ### + + ### smooth edges ? + edges=[];gents.each{|e|edges< 6 + @model.start_operation((db("Extrude Edges by Faces: Smoothing Edge ")),true) + ### 'false' is best to see results as UI/msgboxes... + else + @model.start_operation((db("Extrude Edges by Faces: Smoothing Edge "))) + end + tick=1 + edges.each{|e| + e.soft=true + e.smooth=true + @msg=((db("Extrude Edges by Faces: Smoothing Edge "))+tick.to_s+(db(" of "))+edges.length.to_s) + Sketchup::set_status_text(@msg) + tick+=1 + } + gpx=@model.active_entities.add_group(group) + group.explode + group=gpx + gents=group.entities + @model.commit_operation + end#if + +#=end ### remove this leading # AND above at #=begin ~Line432 to stop extra tools running + Sketchup::set_status_text("") + ### + Sketchup.send_action "selectSelectionTool:" + ### done + end#make_mesh + + + def order_points(edges) + verts=[] + edges.each{|edge|verts< verts.length + ordered_points.reverse! + reversed=true + end#if + end#while + else + ordered_points=[startVert] + counter=0 + while ordered_points.length < verts.length + edges.each{|edge| + if edge.end==ordered_points.last + ordered_points< verts.length + ordered_points.reverse! + reversed=true + end + end + end + ordered_points.uniq! + ordered_points.reverse! if reversed + #Convert vertices to points + ordered_points.collect!{|x|x.position} + if closed + ordered_points<