Is there an easy way to get an array of all the faces that a component lays on?
In the clip below the array returned should be [yellow_face, green_face, blue_face]
Is there an easy way to get an array of all the faces that a component lays on?
In the clip below the array returned should be [yellow_face, green_face, blue_face]
If it is a glue_to component it can be glued to a single face, and it is easy to check this, via:
Sketchup::ComponentInstance#glued_to()
If not, you will need to decide what faces to test.
test_faces = ents.grep(Sketchup::Face)
Youâll need to decide what vertices of the component will be âlaying downâ vertices, and get their 3D point objects in an array, letâs call it lay_pts
.
Then iterate the faces checking if any of the lay points are in the faces.
mating_faces = test_faces.find_all {|face|
lay_pts.any? {|pt|
result = face.classify_point(pt)
result != Sketchup::Face::PointOutside &&
result != Sketchup::Face::PointNotOnPlane &&
result != Sketchup::Face::PointUnknown
}
}
Now this would work using the corner vertices, but would likely miss the green face. So youâll need to add more points at some grid resolution to the lay_pts
array.
You might also try the bounding box intersection approach:
Geom::BoundingBox#intersect()
Pay head to the note about results (of this method) prior to SU2015 !
cbb = cinst.bounds # transformed bounds
lay_bb = Geom::BoundingBox::new.add(
cbb.corner(0), cbb.corner(1), cbb.corner(2), cbb.corner(3)
)
mating_faces = test_faces.find_all {|face|
face.bounds.intersect(lay_bb).valid?
}
Note that I do not know what orientation the component or faces are, so you may need to adjust what the corner()
argument numbers are. See:
Geom::BoundingBox#corner()
I will experiment with some of these methods. They are all new to me so thanks for your help.
That works very well. The only problem is I need a way to check the faces to see if they match the âhole cutting planeâ of the component. This is easy if the component is already glued to a face.
Like this:
mating_faces = test_faces.find_all {|face|
face.bounds.intersect(cinst.bounds).valid? &&
(face.plane==cinst.glued_to.plane)
}
I a case where a component is either glued to a group or nothing how can I get:
cint.gluing_plane
Always check the result of Sketchup::ComponentInstance#glued_to()
for a nil
value, before proceeding.
Ie, to break out of a iteration loop:
break if cinst.glued_to.nil?
or to loop to the next collecton member:
next if cinst.glued_to.nil?
or to bail from a method:
return if cinst.glued_to.nil?
If you glue the component inside the group directly to a face, then the glued_to()
query will return a face object instead.
So, apparently the API is lacking a glued_to_face()
query method, or perhaps an optional argument for the current method, that would drill into groups and other instances and return the glued to face.
Sketchup::Group
objects do not (yet) have a get_glued_instances()
method like faces have.
But perhaps you can go at it from the other direction, and use this to iterate the groupâs collection of faces, finding that one which returns your instance as the one that is glued.
Where cinst
is the component, and group
is the object returned by cinst.glued_to()
:
faces = group.entities.grep(Sketchup::Face)
found = faces.find {|f| f.get_glued_instances.include?(cinst) }
return if found.nil?
glue_plane = found.plane
Thanks.
I already understand how to check what (if anything), a face is glued to. My point rather was that if the component is glued to a face I can get the plane of that face. Otherwise I can compare like this: cint.zaxis == face.normal.
The problem is that a face might be âalignedâ but not on the same plane as the component.
I realize that the glued_to face might not always be the same as the gluing plane of the component. It seems strange that SketchUp allows gluing to a face that is not on plane, thereby distorting the face.
What I was really trying to find out; âIs there a way to tell what the gluing plane of a component is, without checking the glued_to face?â
No worries if that is not possible. In my extension I now display a warning and return, if the component is not glued to a face. I just thought it would have been nice to handle this type of situation as well.
BTW: A component can never be glued a face inside another component of group. Or can it? In a case where it appears to be so the result is that the component.glued_to
returns the group or component containing the face, and the face.get_glued_instances
returns .
Planes in the SketchUp API are represented by arrays.
See: http://www.sketchup.com/intl/en/developer/docs/ourdoc/geom.php
for some handy module methods.
The API defines comparison methods Geom::Point3d#==
and Geom::Vector3d#==
classes for the 2 element plane array type.
The 4 element array types are Floats representing the coefficent of the plane equation.
See: Euclidean plane - Wikipedia
So it is possible to compare them. But be careful with the Floats. You may need to round them to some certain number of decimals for comparison.
Component definitions (I think) use their local XY plane as the gluing plane.
So for example, you need to draw windows lying flat, when you make them into a gluing component.
Try inserting a Marvin window component and hover over the various faces of a cube. (But donât click the insertion point.) Youâll see how the âghostâ component changes orientation as you move over the sides or top.
The definition can also be set to glue to faces in any orientation, only horizontal, only vertical, or none (if the component should not allow gluing.)
Other than that, I donât understand what your trying to say here.
I do not know what this means. I have not seen it. Do you have a screen shot of this, or a sample model showing this has occurred ?
Yes it can, IF the object has been opened for edit, which really means that it is the objectâs definition that is been edited. So if you insert a gluing component into an object opened for edit, then ALL instances of that object will show the change.
Thanks for those links. They were very informative. Iâll admit transformations, vectors, and planes, are still confusing to me. If Iâd do the research I should, I wouldnât need to ask for help from nice people like you.
Slightly annoying if this is not the intended result.
Should probably have been:
This didnât seem to work, because if a component is glued to a group, it means it is not nested inside it. If this is the case, none of the faces inside the group will return the component as being glued to them.
Thanks for going out of your way to educate me.
OK, I did say âperhapsâ. So there is a missing method for the API.
Just happened to think of it, I actually had added a function for that. Iâm sure the same thing could be done for a group.
class Sketchup::ComponentInstance
def get_glued_instances
return self.parent.entities.grep(Sketchup::ComponentInstance).find_all {|c| c.glued_to == self}
end
end
Iâm not sure if adding functionality to SketchUp would be condoned in a public extension.
You should never âmonkey patchâ a class provided in the API, any of the standard Ruby libraries, or any built-in Ruby class. Doing so affects all Ruby code regardless of source and can cause other peopleâs extensions to fail in strange ways! If you want a custom variation on one of these classes, you should use a refinement instead. @DanRathbun had another recent post about refinements.
It would not, and will not pass inspection for the Extension Warehouse.
For ref: Ruby 2.0.0 doc/syntax/refinements.rdoc
module Author::RefinedComponents
refine ::Sketchup::ComponentInstance do
# Returns an array of the externally glued instances if any. (Empty array if none.)
# @return [Array(Sketchup::ComponentInstance)] the glued instances if any.
def get_glued_instances()
parent.entities.grep(Sketchup::ComponentInstance).find_all {|comp|
(comp.glued_to == self) rescue false
}
end
end # class refinement
end # refinement module
using Author::RefinedComponents
module Author::SomePlugin
# Use your refinements here.
end # author's plugin module
Just FYI, the refinement module definition may be kept in a separate library file, and loaded as needed with require()
.
Ok thanks. I was suspicious of that.
I also could go at it like this:
def get_glued_instances(cinst)
return cinst.parent.entities.grep(Sketchup::ComponentInstance).find_all {|c| c.glued_to == cinst}
end
gi = get_glued_instances(cinst)
Yes, as in a method local to your class or plugin module. This is what many do âin a pinchâ just to get the code working.
And it was the preferred pattern before refinements came about in Ruby v2+.
Just an FYI, I have been working on a refinement library. It is in alpha stages at present.
Features to make development easier. Nice.