Dear friends,
“position” Method is used to get the 3D point from the input point. Do you know any Method that can get input point from 3D point?
Scroll up a little in a documentation and check the
Constructor Details
how to create the a new InputPoint object.
def onLButtonDown(flags, x, y, view)
ip1 = Sketchup::InputPoint.new
ip1.pick view, x, y
face1 = ip1.face
p face1
pt2 = Geom::Point3d.new(-3, 0, 2)
ip2 = Sketchup::InputPoint.new(pt2)
face2 = ip2.face
p face2
end
We have face1 but we don’t have face2. I click on pt2. Can you help me for it?
From the very beginning of the Class: Sketchup::InputPoint docu, you can read:
The InputPoint used to pick entities that reside under the current cursor location.
Please check out at the end of the page the #valid?
method too.
So, You have to call a .pick
method on ip2
(similar as you do for ip1 to ‘catch’ valid data what is ‘under’ the mouse cursor location.) Then you can query if there is a face or not…
We have a face on pt2. I wish to select that face not face under the mouse cursor location. How can I select that face?
the parentheses were in the wrong place in my previous post… you maybe misunderstand.
Sorry.
You gave a start point for ip2 with ( ip2 = Sketchup::InputPoint.new(pt2)
)
Then you have to retrieve the pt2
to screen location
/View.#screen_coords-instance_method
x1, y1, z1 = view.screen_coords(pt2).to_a
Then You have to call a .pick
method on ip2
with this coordinates
ip2.pick view, x1, y1
Then you can query if there is a face or not…
Thank you so much. Always you have logical answer for me.
Dear Dezmo,
def onLButtonDown(flags, x, y, view)
ip1 = Sketchup::InputPoint.new
ip1.pick view, x, y
face1 = ip1.face
p face1
p ip1.instance_path.to_a
pt2 = Geom::Point3d.new(-3, 0, 2)
ip2 = Sketchup::InputPoint.new
x1, y1, z1 = view.screen_coords(pt2).to_a
ip2.pick view, x1, y1
face2 = ip2.face
p face2
p ip2.instance_path.to_a
end
face1 and face2 are same. ip1.instance_path return face1 information but ip2.instance_path return nothing. What is my mistake?
I can’t explain that. I have no idea why.I would expect it to return same…
I supposed always face2 will be same but it change when I change view!!! Also ip2.instance_path change when view change. Sometimes return info sometimes don’t. Maybe I am completely in wrong way. I just wish to know group name in pt2 if exist.
you can retrieve the face parent definition and its instances array and get the first instace of it
face2 = ip2.face
# get the parent (it will return Sketchup::ComponentDefinition ... or ..)
p face2.parent
# get the instances of this definition
p face2.parent.instances
# you can use the first one (See note below)
p face2.parent.instances[0]
It maybe works for you in the current situation, but be aware of this:
Copying a group using the copy tool in SketchUp will create copies of the group that share a common definition until an instance is edited manually. If multiple copies are made, all copies share a definition until all copies are edited manually or using
Group#make_unique-instance_method
So more research may be needed …
pt2 is a single 3D point and in my example it is only on one face of one group. I supposed in any circumstances this group will be same. face2 and its parents change when for example our group is behind of another group. any solution?
Then you should avoid the InputPoint for face2
As far as I remember Dan already suggest you the Face.classify_point-instance_method
So something like this could work.
NOTE: I wrote it quickly an did not checked at all… just to give an idea!!
def onLButtonDown( flags, x, y, view )
ip1 = Sketchup::InputPoint.new
ip1.pick view, x, y
face1 = ip1.face
p face1
p ip1.instance_path.to_a
pt2 = Geom::Point3d.new(-3, 0, 2)
# write a new method to get all the faces in a model recursively
# and call it
faces = iterate_ents_for_faces( Sketchup.active_model.entities )
# write a new method to get the first face where the pt2 on it
# using the face.classify_point instance method
face2 = get_face_point_on_it( faces, pt2 )
end
def iterate_ents_for_faces( entities, faces = [] )
entities.each{ |entity|
case entity
when Sketchup::Face
faces << entity
when Sketchup::ComponentInstance, Sketchup::Group
iterate_ents_for_faces( entity.definition.entities, faces )
end
}
faces
end
def get_face_point_on_it( faces, point )
faces.each {|face|
# use face.classify_point instance method
result = face.classify_point(point)
# you might want to consider when the point on the edge
# or vertex as well. Then add it to the condition...
if result == Sketchup::Face::PointInside
return face
end
}
end
I check it and It works well. Thank you so much.
You are welcome!
Why the … are you quoting ( put it into ) your post it again!
Please edit your last post and delete my code from it!
Explanation:
I guess you selected the code to copy it to your computer.
When you are click on the Reply button the forum engine automatically “quote” the selected text into your answer. Please pay attention to this and delete the auto-quote or make sure there is no pre-selected text.
You are right, engine automatically add it. I will be more careful about it. Just I got one problem with your last codes. if faces are in hidden layers,
iterate_ents_for_faces will find them also. How can I solve this problem?
There are lot more…
You extensively need to add more conditions, and considering other ‘unforeseen’ behaviors, etc…etc.
For sure!
First of all I strongly recommend to organize your model that basic geometry (faces, edges) are ALWAYS have a Untagged tag. (layer0) Only the groups and components should be tagged differently. In SU the object not ON or not IN a layer (tag) but they have a layer (tag) ‘properties’.
There are some exceptions…
Have you seen this guide?
https://help.sketchup.com/en/sketchup/controlling-visibility-tags
However of course technically possible.
If you check this
Drawingelement#layer-instance_method
and
Layer#visible?-instance_method
E.g. When you are collecting, you can add a condition so you will get a face if it is visible:
...
faces << entity if entity.layer.visible?
...
I need more practice. I review all of our conversations again and again and each time I try for some improvement. I should check all of my codes and check for layers. Thank you.
Dear Dezmo,
def iterate_ents_for_faces( entities, faces = [] )
entities.each{ |entity|
case entity
when Sketchup::Face
faces << entity if entity.layer.visible?
when Sketchup::ComponentInstance, Sketchup::Group
iterate_ents_for_faces( entity.definition.entities, faces )
end
}
faces
end
def get_face_point_on_it( faces, point )
faces.each {|face|
# use face.classify_point instance method
result = face.classify_point(point)
# you might want to consider when the point on the edge
# or vertex as well. Then add it to the condition...
if result == Sketchup::Face::PointInside
return face
end
}
return nil
end
Codes work if group (point on it) is made by ruby, but cannot work if group made by SU. Can you help me for it?
It seems I have problem with this line.“iterate_ents_for_faces( entity.definition.entities, faces )”. Codes cannot check faces of a group that made by SU.
This does the same, but more concise …
def get_face_point_on_it( faces, point )
faces.find {|face|
# use face.classify_point instance method
face.classify_point(point) == Sketchup::Face::PointInside
}
end
The Enumerable#find
method returns the first matching member of a collection, or nil
if not found.
Try this …
def iterate_ents_for_faces( entities, faces = [] )
entities.each { |entity|
case entity
when Sketchup::Face
faces << entity if entity.layer.visible?
when Sketchup::ComponentInstance, Sketchup::Group
found = iterate_ents_for_faces( entity.definition.entities, faces )
faces.push(*found)
end
}
faces
end