[plugin]Export arcs, circles and vertex to dxf ?
-
Hi, a few year ago, You helped me to do a little plugin to export the outline of selected faces to X:Y coordinates in a text file. (Code below.) Thank you again.
Today, I wanted to separate the arcs, circles and vectors of a selection (I don't need the faces), to export as 2D dxf file (Z=0 for all entities, like for the X:Y plugin below), with three entities (arc, circle, vectors) and be able to use it in a 2D CAD software.
(Some pro laser cutting softwares must have the circle/arc entities to do the cutting interpolation ; if you use only small vectors, like the existing free dxf plugin exporter does, the processing and cutting time could be much much longer, so the price of the cutting is higher.)
It could be a long dxf file, with no groups or order, just one entity after the other, but the circular entities must be described (for example a circle with a center and a radius).I have the informations to write the elementary dxf file, but I don't know (after search) how to get the initial datas from the selection. For example the center and the radius of a full circle. Could you help me?
I'm french, sorry for the english mistakes. My answers can take one or two days, sorry.
Thank you,
Renaud.Here is the code of the face2X:Y plugin :
module RenaudIltis def self.export_face_points selection = Sketchup.active_model.selection if selection.empty? UI.messagebox("Nothing selected, export canceled") else # Count how many faces are in the current selection => must be > 0 face_count = 0 # Look at all of the entities in the selection. selection.each { |entity| if entity.is_a? Sketchup;;Face face_count = face_count + 1 end } if face_count > 0 # Ask for the file path. filepath = UI.savepanel("Export selected faces",nil,"*.txt") # Don't continue when the user cancelled return if filepath.nil? # Test of the file extension filepath = filepath.tr("\\","/")#in case any PC ruby weirdness... if File.basename(filepath,".*") == File.basename(filepath) #the suffix is right or missing filepath=File.join(File.dirname(filepath), File.basename(filepath,".txt") + ".txt") #if the suffix is missing or right else if File.basename(filepath,".*") + ".txt" != File.basename(filepath)#the suffix is different than .txt answer = UI.messagebox("Filename has not the '.txt' extension. Change your extension?", MB_YESNO) if( answer == 6 ) filepath=File.join(File.dirname(filepath), File.basename(filepath,".*") + ".txt") end else filepath=File.dirname(filepath) + "/" + File.basename(filepath,".txt") + ".txt" #if the suffix is missing end end begin # Open a file for writing File.open(filepath, "w"){ |file| selection = Sketchup.active_model.selection # Get an array of faces that are in the selection. faces = selection.grep(Sketchup;;Face) faces.each_with_index{ |face, index| # Write a label for the face. file.puts("Face#{index+1}") # Get a transformation object that translates from model space to 2d space of the face. t = Geom;;Transformation.axes(face.vertices.first.position, *face.normal.axes).inverse # Write all vertices to the file. blnFirstPoint = true first_point_u=0 first_point_v=0 face.outer_loop.vertices.each{ |vertex| # Get the point of the vertex and apply the transformation. point = vertex.position.transform(t) # Convert the coordinates u, v = point.to_a.map{ |c| c.to_f } if blnFirstPoint==true first_point_u = u first_point_v = v blnFirstPoint = false end #if # Write the coordinates to the file. file.puts("#{(u*10000*25.4).to_i.to_f/10000};#{(v*10000*25.4).to_i.to_f/10000}") } file.puts("#{(first_point_u*10000*25.4).to_i.to_f/10000};#{(first_point_v*10000*25.4).to_i.to_f/10000}") } } UI.messagebox("The file is here ;" + filepath) rescue SystemCallError => e if e.message =~ /(No such file or directory)/ UI.messagebox("Error, the file was not created. Be careful if you are using an older version of SketchUp, the full file path must not contain special characters. The full file path you requested is " + filepath) else fail() #re-raise the last exception end end else UI.messagebox("No faces in the selection, export canceled") end end end # This will run only once when the file is loaded the first time. unless file_loaded?(__FILE__) # Add the method to the menu. command = UI;;Command.new("Export selected faces to X;Y file"){ self.export_face_points } command.small_icon = "faces2xy/faces2xy_icon_16.png" command.large_icon = "faces2xy/faces2xy_icon_24.png" command.tooltip = "Export selected faces to X;Y file" command.menu_text = "Export selected faces to X;Y file" menu=UI.menu("Plugins") menu.add_item(command) tb = UI.toolbar("Selected faces to X;Y") tb.add_item(command) if tb.get_last_state == TB_VISIBLE UI.start_timer(0.1, false) { tb.restore } elsif tb.get_last_state == TB_NEVER_SHOWN tb.show end file_loaded(__FILE__) end end
-
circles = [] Sketchup.active_model.selection.grep(Sketchup;;Edge).each{|e| c = e.curve ### it's nil if a non-curve edge if c && c.is_a?(Sketchup;;ArcCurve) ### might be a circle or an arc circ = true c.vertices.each{|v| ### vertex has at least edges, but are there at least 2 and are both in the curve es = 0 v.edges.each{|ee| es += 1 if c.edges.include?(ee) } if es != 2 ### it's an arc circ = false break end } else ### it's not a curve, or if it is it's not a circle or an arc circ = false next end circles << c if circ && ! circles.include?(c) ### only add it to list once } circles.each{|c| ### get circle's properties here, e.g. p c.center p c.radius p c.normal }
-
Hello TIG,
Thank you very much , I will try to do a first sample.
If you have the time to answer :
1/ Could you look the adds in your code (below), to get the arc entities. Am I right?
2/ If circ=false, how to get the Sketchup points of the entity?Renaud
circles = [] arcs = [] Sketchup.active_model.selection.grep(Sketchup;;Edge).each{|e| c = e.curve ### it's nil if a non-curve edge if c && c.is_a?(Sketchup;;ArcCurve) ### might be a circle or an arc circ = true arc = false c.vertices.each{|v| ### vertex has at least edges, but are there at least 2 and are both in the curve es = 0 v.edges.each{|ee| es += 1 if c.edges.include?(ee) } if es != 2 ### it's an arc arc = true break end } else ### it's not a curve, or if it is it's not a circle or an arc circ = false next end circles << c if circ && ! arc && ! circles.include?(c) ### only add it to list once arcs << c if circ && arc && ! arcs.include?(c) ### only add it to list once } circles.each{|c| ### get circle's properties here, e.g. p c.center p c.radius p c.normal } arcs.each{|c| ### get arcs's properties here, e.g. p c.center p c.radius p c.normal p c.start_angle p c.end_angle }
-
I think you have an error in collecting the circles and arcs.
if es != 2 ### it's an arc arc = true circ = false break end
later
circles << c if circ && ! circles.include?(c) ### only add it to list once arcs << c if arc && ! arcs.include?(c) ### only add it to list once
-
OK, right.
-
Hello TIG,
When arc=false and circle=false, I wanted to store the entity in an array, could y help me? So at the end, I will use the edges of these entities for writing the polylines.
-
You now have two arrays - for circles and arcs.
Process each collected 'curve' in turn.
e.g.circles.each{|c| c.edges.each{|e| # the curve's edges # process each edge 'e' } }
Do the same for the 'arcs' array...
As it stands, you have arrays of curves which define circles of edges.
Those 'collections' are pointing to their 'edges' - i.e. defining their 'segments', which can be used as you want later...
-
I misspoke, sorry. I'm OK for the arc and circle. They will be writen in the DXF file as ARC entity and CIRCLE entity.
What I don't see is how to collect the edges of the vertices of other entities of the selection/loop to write polylines (it's better than just lines for selection in the CAD softwares), when it's not an arc or a circle, in the "else" section of the previous code :else ### it's not a curve, or if it is it's not a circle or an arc circ = false arc = false ... next end
To write as polylines the dxf entities which are not circle or arc, I will use the following functions(*). The function dxf_write_polyline must be modified, because it's based on the loops of the faces, and the loop will be broken - or ignored - by the arcs and circles.
tform=Geom;;Transformation.new() layername=model.active_layer.name def dxf_transform_vertex(vertex, tform) point = Geom;;Point3d.new(vertex.position.x, vertex.position.y, vertex.position.z) point.transform! tform point end def dxf_write_polyline(face, tform, layername) face.loops.each do |aloop| $dxf_file.puts(" 0\nPOLYLINE\n 8\n"+layername+"\n 66\n 1") $dxf_file.puts("70\n 8\n 10\n0.0\n 20\n 0.0\n 30\n0.0") for j in 0..aloop.vertices.length do if (j==aloop.vertices.length) count = 0 else count = j end point = dxf_transform_vertex(aloop.vertices[count],tform) $dxf_file.puts( " 0\nVERTEX\n 8\nMY3DLAYER") $dxf_file.puts("10\n"+(point.x.to_f * $unit_conv).to_s) $dxf_file.puts("20\n"+(point.y.to_f * $unit_conv).to_s) $dxf_file.puts("30\n"+(point.z.to_f * $unit_conv).to_s) $dxf_file.puts( " 70\n 32") end if (aloop.vertices.length > 0) $dxf_file.puts( " 0\nSEQEND") end end end
Thank you very much.
(*)existing plugin from http://www.guitar-list.com, original authors: Nathan Bromham, Konrad Shroeder
-
Hi,
In fact, there is the problem of the order of the vertices to make the polylines. I think I must follow the loops, like in the initial code of guitar-list, but I must test the ".curve" of each vertex and extract the arcs, circles, and the polylines with vertices in the order. A little tricky for me, I will take a paper and a pencil! -
Look at my 'Weld' tool.
That takes selected edges, and then welds them into a curve.
It has to sort the edges out in order and also get the start/end points correctly ordered.However, a non-arc curve has a list of ordered vertices method, so you can get their positions as points using:
points = curve.vertices.collect{|v| v.position }
then use
points.each_with_index{|p, i| model.active_entities.add_text(i.to_s, p) }
to label the points to demonstrate to yourself that they are indeed ordered... -
Thanks TIG, I will work on it.
-
Hello TIG,
Like other people, I have the following problem : with the(Sketchup::ArcCurve)
entities, the arcs are always rotated, with the.start_angle
value equal to 0.0 (and not equal to the angle with the X axe, the API documentation is wrong on this point in my situation - working with the entities of the loops).
Do you have a clean (and 3D) workaround?
Best regards,
Renaud. -
I just saw that the .xaxis propery of the arcs are rotated => start_angle=0 is right, because the reference is wrong. OK, knowing that, I can see how to do this.
Advertisement