• Login
sketchucation logo sketchucation
  • Login
⚠️ Libfredo 15.4b | Minor release with bugfixes and improvements Update

[plugin]Export arcs, circles and vertex to dxf ?

Scheduled Pinned Locked Moved Extensions & Applications Discussions
extensions
13 Posts 2 Posters 2.5k Views 2 Watching
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • I Offline
    Iltis
    last edited by 1 Aug 2016, 08:05

    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
    
    
    1 Reply Last reply Reply Quote 0
    • TIGT Offline
      TIG Moderator
      last edited by 1 Aug 2016, 13:10

      
      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
      }
      
      

      TIG

      1 Reply Last reply Reply Quote 0
      • I Offline
        Iltis
        last edited by 3 Aug 2016, 12:06

        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
            }
        
        
        1 Reply Last reply Reply Quote 0
        • TIGT Offline
          TIG Moderator
          last edited by 3 Aug 2016, 12:46

          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

          TIG

          1 Reply Last reply Reply Quote 0
          • I Offline
            Iltis
            last edited by 3 Aug 2016, 12:53

            OK, right.

            1 Reply Last reply Reply Quote 0
            • I Offline
              Iltis
              last edited by 11 Aug 2016, 19:57

              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.

              1 Reply Last reply Reply Quote 0
              • TIGT Offline
                TIG Moderator
                last edited by 11 Aug 2016, 20:42

                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...

                TIG

                1 Reply Last reply Reply Quote 0
                • I Offline
                  Iltis
                  last edited by 12 Aug 2016, 04:23

                  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

                  1 Reply Last reply Reply Quote 0
                  • I Offline
                    Iltis
                    last edited by 12 Aug 2016, 07:45

                    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! 😄

                    1 Reply Last reply Reply Quote 0
                    • TIGT Offline
                      TIG Moderator
                      last edited by 12 Aug 2016, 11:18

                      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...

                      TIG

                      1 Reply Last reply Reply Quote 0
                      • I Offline
                        Iltis
                        last edited by 12 Aug 2016, 11:51

                        Thanks TIG, I will work on it.

                        1 Reply Last reply Reply Quote 0
                        • I Offline
                          Iltis
                          last edited by 17 Aug 2016, 19:59

                          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.

                          1 Reply Last reply Reply Quote 0
                          • I Offline
                            Iltis
                            last edited by 18 Aug 2016, 05:17

                            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.

                            1 Reply Last reply Reply Quote 0
                            • 1 / 1
                            • First post
                              Last post
                            Buy SketchPlus
                            Buy SUbD
                            Buy WrapR
                            Buy eBook
                            Buy Modelur
                            Buy Vertex Tools
                            Buy SketchCuisine
                            Buy FormFonts

                            Advertisement