Creating a bounding face around an instance
-
Hello dear Ruby coders,
Im making a script that places a window/door component which i have placed on a wall, into that wall.
So it has to define all outer corners that are glued to the wall, then make a face onto that wall and push/pull this away so a hole is made into a wall.I have my script working, the only problem is that it only works when my wall is on a x or y axis. The reason for this is that i define my corner points of the window/door with the Boundingbox, and then check which of those points is on the face of my wall.
My problem is that the bounding box of an object is always orthogonal so when i try to place a window in a wall thats not paralel to a x or y axis, there are no bbox corners touching my wall.Has anyone an idea to define the corners of my push/pull face in a different way?
Here is the code where i define my corners of the push/pull face with the coordinates of the bbox corners.
Its one of my first rubie scripts so the code is quite messy and inefficient I guess...
Thanks for any help!#requesting all corners of the bbox @@bbox = @@kozijn.bounds #save all corners of the bbox in an array @@pt = [] @@pts = [] @@pt[1] = @@bbox.corner 0 @@pt[2] = @@bbox.corner 1 @@pt[3] = @@bbox.corner 2 @@pt[4] = @@bbox.corner 3 @@pt[5] = @@bbox.corner 4 @@pt[6] = @@bbox.corner 5 @@pt[7] = @@bbox.corner 6 @@pt[8] = @@bbox.corner 7 m = 1 if @@nested == "true" #@@nested says if the instance is in a group or not for q in @@group.entities if q.typename == "Face" #Check if corners of the bbox are on the face for n in (1..8) if q.classify_point(@@pt[n]) == 1 || q.classify_point(@@pt[n]) == 2 || q.classify_point(@@pt[n]) == 4 @@pts[m] = @@pt[n] m = m + 1 glued = q #define which face the points are glued to end #if end #for end #if end #for @@kozijn.glued_to = glued @@new_face = @@group.entities.add_face @@pts[1],@@pts[2], @@pts[4], @@pts[3] else #define all points glued to a face for n in (1..8) if @@kozijn.glued_to.classify_point(@@pt[n]) == 1 || @@kozijn.glued_to.classify_point(@@pt[n]) == 2 || @@kozijn.glued_to.classify_point(@@pt[n]) == 4 @@pts[m] = @@pt[n] m = m + 1 end end @@new_face = @@entities.add_face @@pts[1],@@pts[2], @@pts[4], @@pts[3] end #if
-
You could align your model axis to your windows before turning it into a component. Then the bounding box will align to the window snugly.
Then to get the bounding box coordinates for you component, simply get the bounding box coordinates from the component's definition (the definition is placed on 0,0,0) and transform them by the components actual transformation. THe code might look something like this:
my_comp = a_component t = my_comp.transformation comp_def = my_comp.definition def_t = comp_def.bounds.corner(0) new_t = t * def_t
That final variable, new_t will be the real world location of the corner(0) of the component. Multiply any of the bounding box corner's you need by the transfomation like I showed to get their real world coordinates.
Does that help at all? I'm not positive I answered the right question,
Chris
-
Hi Chris,
Thanks, I will try this. I'm not sure if the the bounding box will align to the new axes or will keep orientated to the old axes.
Wouldnt there be another method to define the outer corners of the window that are touching the wall? I'm not positive that using the bounding box is the way to go.I'll give it a try anyway
thanks!
-
The bounding box will align to the newly set axis.
I agree that using the bounding box is not the most ideal way to to do it. It is how you said you wanted to to do it, so I was just suggesting how to make it work.
What is your plugin trying to do, and what is the actual workflow that is expected for the user. That mgiht help come up with a workable solution.
Chris
-
What my plugin should do is as follows:
The user selects a window component(dynamic component with variable width and height).
User places this component on a wall
user selects my function (while window is selected)
Functions does:
-recognize which face the component is glued to
-determine the corner points of te component
-create a face which is as big as the component (the face is on the same place on the wall)
-determine thickness of the wall
-push pull the newly created face into the wall
-place the component in the middle of the wallbasicly i have everything working on orthogonal walls. Problem is determining the corner points of the component when its on a nonorthogonal wall.
thanks for thinking with me
-
Make an empty temp group.
Add an instance of the component to it at the ORIGIN.
Make a a new face at z=0 with normal [0,0,-1] that is somewhat bigger that the component's XY bounding box.
Get the face's outer edges as an array.
Intersect the face with the component.
Erase the outer edges from the array.
Now the remaining face.outer_loop.edges will equal the cutting shape of the component
Get an array of the face.outer_loop.vertices and then convert those to their points.
Now get the transformation of the inserted component and apply that to these points.
You now have a list of points on the 'wall' outer face that correspond to the component's cutting hole.
You can erase the original temp group***.
Project these points using a raytest from their location along the vector face.normal.reverse
The first thing they hit will be the back face of the 'wall' - the point is what you want - this is returned in raytest_result[0] - check it's a face with raytest_result[1][-1].
You now have a list of points on the back face of the 'wall' projected from its front face.
Use these points to make a new face on the inner surface.
PushPull the face till it meets the front where the component is cutting its hole.
***When you make the temp component you can work out how deep it already cuts into any face it's glued on to by the amount of its bounding-box below Z=0 where it intersected with the temp face - use this as the maximum PushPull value so the inner reveals return just to the component's rear faces...
To make it really clever link the component-instance with the parts forming the inner hole with attributes - so it one is erased the other goes to, or it one is moved the other moves with it...
-
@tig said:
Make an empty temp group.
Add an instance of the component to it at the ORIGIN.
Make a a new face at z=0 with normal [0,0,-1] that is somewhat bigger that the component's XY bounding box.
Get the face's outer edges as an array.
Intersect the face with the component.
Erase the outer edges from the array.
Now the remaining face.outer_loop.edges will equal the cutting shape of the component
Get an array of the face.outer_loop.vertices and then convert those to their points.
Now get the transformation of the inserted component and apply that to these points.
You now have a list of points on the 'wall' outer face that correspond to the component's cutting hole.
You can erase the original temp group***.
Project these points using a raytest from their location along the vector face.normal.reverse
The first thing they hit will be the back face of the 'wall' - the point is what you want - this is returned in raytest_result[0] - check it's a face with raytest_result[1][-1].
You now have a list of points on the back face of the 'wall' projected from its front face.
Use these points to make a new face on the inner surface.
PushPull the face till it meets the front where the component is cutting its hole.
***When you make the temp component you can work out how deep it already cuts into any face it's glued on to by the amount of its bounding-box below Z=0 where it intersected with the temp face - use this as the maximum PushPull value so the inner reveals return just to the component's rear faces...
To make it really clever link the component-instance with the parts forming the inner hole with attributes - so it one is erased the other goes to, or it one is moved the other moves with it...
Wow thanks alot!
Im gonna work on this.Regards,
Quintus -
Tig's methods sounds correct but he missed the point that the "user" will be placing this window first and then running the script. There may be a simpler solution to this problem...
For me an ideal situation would be to tag the points that will rest on the "wall face". Then its just a matter of saying to the component HEY!, where are pt1, pt2, pt3, and pt4, located right now? this will make the job so much more easier.
So the much more simplified outline would be as follows
First what are the facts we can query at runtime of the script...?
- the face upon which this componet will be cutting (CI.glued_to?)
- the four corners within the component that will touch "this" face
With these two simple facts all one needs to do is create a loop on the face using the four points (or do an intersect of component and face and then search for the appropriate "hole loop") and voila! You know what to do next
Of course it's easy to outline a problem but i think my logic is sound, let me know if there are any holes here...?
-
Thanks Im going to try both.
Now I can't seem to get the selecting device to work. I want to select the 2 oposite corners in the component but the best_picked doesnt support corners or intersections. Which function in the pickhelper should i use to get grip on a corner? ( Like the Line tool does)
thanks!
-
Use an inputpoint to get all the SketchUp inference points. This is a bare-bones code snippet that will make a tool, use an inputpoint and then draw that inputpoint to the screen.
` class SUC_IP_POINT
def activate @ip1 = Sketchup::InputPoint.new end def onMouseMove(flags, x, y, view) @ip1 = view.inputpoint x,y view.invalidate end def draw(view) @ip1.draw view end
end
Sketchup.active_model.select_tool(SUC_IP_POINT.new)`
So check that out, see if it helps.
Chris
Advertisement