Get face vertices from a group


#1

Basic question… How can I get the face vertices from a group? I know the group name. I want to get the vertices of all the faces. I want to write them to a text file and use them externally.

Thanks,


#2

Do you care what format the text file uses, or is the critical issue to just generate readable text vs the normal SketchUp file’s binary data? There are existing text-based 3D formats such as dxf, and if you can use one of them you should will be able to employ one of SketchUp’s 3D exporters (assuming you have SketchUp Pro).

If you need a non-standard format or have Make, you will have to find or write a SketchUp Ruby program that does what you want - which begs the questions: are you familiar with Ruby programming and the SketchUp Ruby API? The task is not terribly difficult if you have these skills.


#3

the basic are all in the API

model = Sketchup.active_model
ents  = model.entities
target = ents[0]
tents = target.entities
faces = tents.grep(Sketchup::Face)
verts = []
faces.each {|f| verts << f.vertices }
# this will return a comma separated face vert set on each line
# add a delimiter that you chop! at the start and end of each line
list = ','
verts.each do |vset|
  list.chop! << "\n"
  vset.each do |vert|
    # to_a will force using internal unit of 1 inch...
    list << vert.position.to_a.to_s + ','
  end
end
list.chop!

you need to write list out to file using standard ruby File methods…

john


#4

Thanks for your reply. I have tried that but i am getting
Error: #<NoMethodError: undefined method `entities’ for #Sketchup::Edge:0x0002af193b3010> at tents = target.entities

The target is the name of the group right? I have a group named target, but still it is giving error.


#5

No. target is the name of a variable that is supposed to reference the group. But the statement

target = ents[0]

just grabs the first entity in the model, which presumes that the only content of your model is the group you want to process. It is finding an edge instead, and edges don’t have an entities collection.

You should code a way that explicitly gets the group of interest. For example, select the group in the GUI before running the Ruby. Then replace the statement above with

target = Sketchup.active_model.selection[0]

#6

Thank you so much. That worked. The vertices i get are in inches right?


#7

Yes. All positions in SketchUp are stored internally in inches. If you want them in other units, you will need to convert. There are methods in the API to do the conversions.


#8
# vert.position.to_s  returns model units i.e. 25.4mm, 2.54cm, 0.0254m or 1"
# you would need to clean to use as raw numbers in anther app [I assume]
list << vert.position.to_s.tr('mc\'\"', '') + ','

john


#9

NO, Sketchup::Vertex#position() returns a Geom::Point3d object which is always in inches.

Do not confuse the output of the Console, with the return from an API method.
The console automatically and transparently calls an object’s #to_s method.

So, it is really the Geom::Point3d#to_s() method that is returning a string representationin model units” of the point returned by the vertex.position call.


Sorry to jump on this but, …

Someone making changes to the API docs, has this “console confusion” (or “string interpolation confusion”,) and is peppering the docs with invalid statements about the return of points and lengths being “in model units”, when in fact they are not.

See recent comments in the Ruby API Stubs repo issues:


#10

When serializing 3d data, don’t use Length.to_s as it will be dependent on the current user’s locale. (The decimal separator will be different.) You should convert any Length to Float before serializing.


#11

good point, I was being very simplistic…

you also need to check for parent scaling and apply it…

i.e. a unit cube inside a scaled group will return unit vert.positions not scaled unit vert.positions…

did that come out right?

john


#12

I have applied the transformation and it worked. I am also not converting it to string, instead i am using them in inches.


#13

Along with the vertices, I also want to write the transformation matrix(xy plane) to the text file. I have tried this, but as the looping through faces is done at the top, I always get the last face’s transformation I guess.

def GetFaces
     filePath = @modelPath + @modelName + "_Sketchup"+"\\FacadeFaces.txt"
	 target = Sketchup.active_model.selection[0]      
	 t = target.transformation 
     tents = target.entities
     faces = tents.grep(Sketchup::Face)
     verts = []     	
     transformationMatrix = []	 
     faces.each {|f| 
	 verts << f.vertices 
	 axes = f.normal.axes
	 origin = f.bounds.center
	 transformationMatrix = Geom::Transformation.axes(origin, axes[0], axes[1], axes[2]).inverse
	 }     
     list = ','
     verts.each do |vset|
     list.chop! << "\n"
     vset.each do |vert|    
	 pos = vert.position.transform! t
	 list << pos.to_a.to_s.tr('[]','').tr(',','') + ','	 	 
  end
  list << ';' + transformationMatrix.to_a.to_s.tr('[]','').tr(',','')
end
list.chop!
f=File.new(filePath, "w+") 
File.write(filePath, list)
f.close()
 end

#14
# keep them together in a nested array
both = []
both << [ f.vertices,  transformationMatrix ]

# then later
both.each do |verts, tran|
# code to format each line
list << formatted_pos + formatted_tran
end

john


#15

You set the value of transformationMatrix at the bottom of the faces.each block, so of course it is overwritten on each pass and all you see is the one for the last face. If you want all the matrices, you will need to accumulate them in an Array the way you are doing for verts.


#16

Is there any way to check if the face has a hole( or holes) and if it has any, get the outer loop vertices (boundary vertices) ?


#17

To get the loop[s]…

outer_loop = face.outer_loop

  • this loop’s vertices are returned ccw,
    relative to the face.normal

inner_loops = face.loops - [outer]

  • an array of loops | | if none == [ ]
    each loop’s vertices are returned cw,
    relative to the face.normal

To get the vertices use:

some_vertices = some_loop.vertices


#18

Thank you.


#19

How can I get the name(instance) of the selected group ? I want to loop through the selection and get the group name of each selection.

target = Sketchup.active_model.selection
target.each do |sel|
// get the name of selected group
end


#20
group_names={} # a hash for each group & its name [if any]
Sketchup.active_model.selection.grep(Sketchup::Group).each{|g|
  group_names[g]=g.name
}