Unfortunately I got same result. What else can I do?
# encoding: UTF-8
#{ =========================================================
# Documentation block ...
#} =========================================================
require 'sketchup.rb'
module MajidMahmoudi
module BoxTest
class MajBox
def init()
@lay = Sketchup.active_model.layers
@st = 0
end
def activate
init()
Sketchup.active_model.active_layer = @lay.add('Layer1')
pt1 = [-5, 0, 0]; pt2 = [5, 0, 0]; pt3 = [5, 10, 0]; pt4 = [-5, 10, 0]
grp1 = Sketchup.active_model.active_entities.add_group
face1 = grp1.entities.add_face pt1, pt2, pt3, pt4
face1.pushpull -10
end
def onLButtonDown( flags, x, y, view )
Sketchup.active_model.active_layer = @lay.add('Layer1')
ip1 = Sketchup::InputPoint.new
ip1.pick view, x, y
pt2 = ip1.position
faces = iterate_ents_for_faces( Sketchup.active_model.entities )
face2 = get_face_point_on_it( faces, pt2 )
if face2
p "Face2 = ", face2
else
p "Face2 = nil"
end
end
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
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
end
UI.menu("Plugins").add_item("MajBox") {
Sketchup.active_model.select_tool(MajBox.new)
}
end
end
This codes make a group. If you make another group by SU then click on each group you will got different result in Ruby Consul.
This group have it’s “local coordinate system”. It’s origin (it’s axes intersection) is exactly the same location as the model “global coordinate system”. Therefor the points in it, relative and absolute coordinates numerically will be same.
You might have this group coordinate system elsewhere. Actually this is the situation now.
When you queering the ip1.position
, you will get the coordinates in global system, but he clicked face inside the group have a different (local) coordinates.
Fortunately the InputPoint#transformation-instance_method retrieves the Transformation object for the input point.
You have to use inverse transformation on the pt2
in question:
Try with this modification:
...
face2 = get_face_point_on_it( faces, pt2.transform(ip1.transformation.inverse) )
if face2
p "Face2 = #{face2}"
...
TIP: Go to menu
Window>> Model Info >> Component
and check the “Show component axes” to see the “coordinate systems” of components / groups
Really interesting problem. Your new codes sometimes work and sometime don’t also it depend on model view. by the way, at the end I wish to find faces that a 3D point is on it I just used inputpoint to show my problem. (I.E we have pt2 and don’t have ip1). Can you help me for it?
InputPoint uses inferencing.
It is very similar (if not the same) as you see, when you are e.g. using the native Line tool.
If the yellow tooltip - beside the coursor - shows the “On face…” you can be sure that the cursor get position on the face. And the first point will be created on face:
But if you see something like “From point” even it looks like the cursor is above the face actually it is not creating the point on face but above…
In your example this kind of tooltip is not implemented. Therefore you will never be sure if the “click” point on the face or not.
There is an other, similar to Imputpoint, the PickHelper method
This one can determine the picked face without a “disturbance” of inferencing.
It has it’s own method to get a transformation at a specific pick path… It is a little more complicated to retrieve but not that much.
You should apply transformation on the 3D point in question, similar as we did in the previous example with pt2
, which was determined by Imputpoint position. (I assume 3D point cooordinates given as model (global) cooordinates .)
So both method (in Imputpoint or PickHelper) returns the Transformation of the component instance or group containing the clicked face. You heve to use the inverse of retrieved transformation on the 3D point to get into same coordinate system.
My 3D point come from math calculation and not related to InputPoint at all. We have this 3D point in view or not, I wish to know face that this point is on it. As you said, when coordinate system is in it’s origin, codes work good but when use local coordinate system cannot find face. Is it possible at first we change group coordinate system to origin then find face and return coordinate system?
Even I don’t know how to move axes of a group to point 0, 0, 0!!! Although I don’t know it can help or not but when I change in SU, it works. Would you please help me for it?
You have to query the parent group of face, and get the transformation of it.
Then apply this transformation inverse to the questionable point.
E.g.:
def create_box
pt1 = [-5, 0, 0]; pt2 = [5, 0, 0]; pt3 = [5, 10, 0]; pt4 = [-5, 10, 0]
grp1 = Sketchup.active_model.active_entities.add_group
face1 = grp1.entities.add_face pt1, pt2, pt3, pt4
face1.pushpull -10
vector = Geom::Vector3d.new(5, 5, 5)
tr = Geom::Transformation.translation(vector)
grp1.transform!(tr)
end
def get_face_point_on_it( faces, point )
faces.find {|face|
group = face.parent.instances[0]
tr = group.transformation
point_tr = point.transform(tr.inverse)
p point_tr.to_a
face.classify_point(point_tr) == Sketchup::Face::PointInside
}
end
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
create_box
faces = iterate_ents_for_faces(Sketchup.active_model.entities)
face_point_on_it = get_face_point_on_it( faces, Geom::Point3d.new(5, 10, 15) )
If the face in a group and this is in a group… etc. You have to do recursively and get the combined transformation.
There is a code already in the forum to how to do that .
I’ll leave you with the joy of searching.
Answered in other topic.
You let me enjoy Ruby Sketchup so much. You are great.
def iterate_get_face_point_on_it( point )
ent = Sketchup.active_model.active_entities
ent.each{ |entity|
case entity
when Sketchup::Face
if entity.layer.visible?
result = entity.classify_point(point)
return entity if result == Sketchup::Face::PointInside
end
when Sketchup::ComponentInstance, Sketchup::Group
if entity.layer.visible?
tr = entity.transformation
point_tr = point.transform(tr.inverse)
entg = entity.definition.entities
entg.each{ |entityg|
case entityg
when Sketchup::Face
result = entityg.classify_point(point_tr)
return entityg if result == Sketchup::Face::PointInside
end
}
end
end
}
return nil
end
just want to show how much I do practice with your codes. Combined iterate and get. Also I don’t have sub group.
Sorry to bother you again!!! In following if group need transformation, line will draw in different place but face2 is right. Can you tell me how can I solve this problem? (return group reference point to its original).
def onLButtonDown( flags, x, y, view )
ip1 = Sketchup::InputPoint.new
ip1.pick view, x, y
pt2 = ip1.position
faces = iterate_ents_for_faces( Sketchup.active_model.entities )
face2 = get_face_point_on_it( faces, pt2 )
grp = face2.parent.instances[0]
ents = grp.entities
line = ents.add_line pt2, [pt2.x, pt2.y, pt2.z + 20]
if face2
p "Face2 = #{face2}"
else
p "Face2 = nil"
end
end
Most probably because :
“…position method on a input point always returns a point that is transformed into model space…”
as you can read here
InputPoint#transformation-instance_method
You got the face2 right because the method finding it is designed to work with model ordinates of point.
Now - as far as I see - you want to draw a line into a group which have different coordinate system.
Reading further down of above link text:
“… If you are using the edge, face or vertex method on the InputPoint though, you will probably need to use the transformation method to transform the data that you get back from the selected entity.”
Meaning that you can get the transformation of the point related to the face related to group.
(Note that this transformation is a same as you retrieved earlier for the group)
So something like this should work…
....
ents = grp.entities
# corrected
tr_ip1 = ip1.transformation.inverse
#corrected
pt2tr = pt2.transform( tr_ip1 )
line = ents.add_line pt2tr, [pt2tr.x, pt2tr.y, pt2tr.z + 20]
....
I hope you have been checked
my other answer for you
about the transformations.
As you realise the transformations are tricky things in SU Ruby API, you need a lot of time , “trial and error” to understand.
Myself just learning too. So, could be some mistakes in my “examples”.
I try to find my problem but cannot find it. I made following ruby code to show my problem.
# encoding: UTF-8
#{ =========================================================
# Documentation block ...
#} =========================================================
require 'sketchup.rb'
module MajidMahmoudi
module BoxTest
class MajBox
def activate
end
def onLButtonDown( flags, x, y, view )
ip1 = Sketchup::InputPoint.new
ip1.pick view, x, y
pt2 = ip1.position
grp = iterate_get_face_point_on_it( pt2 )
ents = grp.entities
line = ents.add_line pt2, [pt2.x, pt2.y, pt2.z + 20]
grp.model.close_active
end
def iterate_get_face_point_on_it( point )
ent = Sketchup.active_model.active_entities
ent.each{ |entity|
case entity
when Sketchup::ComponentInstance, Sketchup::Group
p "Group = #{entity}"
return entity
end
}
return nil
end
end
UI.menu("Plugins").add_item("MajBox") {
Sketchup.active_model.select_tool(MajBox.new)
}
end
end
Please make a box as a group (not in global coordinate system)in SU and click on it. You will see line will be in different point but pt2 didn’t change. I need to know problem and only you can help me for it. Thank you in advance.
I did not checked before…So I was wrong, sorry!
You should apply an inverse transformation…
class MajBox
def activate
end
def onLButtonDown( flags, x, y, view )
ip1 = Sketchup::InputPoint.new
ip1.pick view, x, y
pt2 = ip1.position
tr_ip1 = ip1.transformation.inverse
pt2_tr = pt2.transform(tr_ip1)
grp = iterate_get_face_point_on_it( pt2 )
ents = grp.entities
line = ents.add_line pt2_tr, [pt2_tr.x, pt2_tr.y, pt2_tr.z + 20]
# grp.model.close_active
end
def iterate_get_face_point_on_it( point )
ent = Sketchup.active_model.active_entities
ent.each{ |entity|
case entity
when Sketchup::ComponentInstance, Sketchup::Group
p "Group = #{entity}"
return entity
end
}
return nil
end
end
I should be more careful about Global and Local coordinate system. Thank you so much
May I ask you to answer my quoestion:
Have been checked
my answer for you in other topic
about the transformations?
I will back to other topic in few days. I need time to finish this topic. For sure many many times I will back to your posts as I did. It is so interesting for me that you answer my many questions before I ask!!!
You ask quite succinctly (briefly), so many times I just assume what you want …
That’s why I’m trying to figure out what I would ask if I were in your situation.
tr = grp.transformation
grp = grp.transform! tr.inverse
grpent = grp.definition.entities
grpent.transform_entities(tr, grpent.to_a)
# Edit Group
grpent = grp.definition.entities
grpent.transform_entities(tr.inverse, grpent.to_a)
grp = grp.transform! tr
You are great!!!