[Plugin] 2dBoolean ver1.3.1 beta UPDATE 20 dec 2013
-
Here's a video tutorial on using the plugin for stamping stone patterns into various shapes. So far I've had great results. Thanks again Joel and TIG!
[flash=800,600:1trov9v7]http://www.youtube.com/v/SNTQDBmKIro[/flash:1trov9v7]
-
Earthmover!
That's quite a demonstration. Really! I can see here experienced modelers can find new workflows. Nice use of styles too.
I know it's a bit slow when having a lot of geometry. It will be faster in Hatchfaces (tiled patterns without faces).
Anyway, thank you for a nice video.
-
I'm wondering if the "hole" issue can be solved at all using face.classify method.
Watching Eartmover movie one can see he using a lot of detail in his meshes. Doing that, you will probably get faces and edges erased from holes, of the face it's glued to. Wich is the desired result!
But if you are using less geometry for intersecting! For ex just a 2d square covering some holes. The face covering the hole will not be deleted cause there arent any vertices in the hole. The same if you have an edge crossing over the hole it will be assumed to be outside the hole, and therefore not deleted.
Now, I have come so far to create a new group inside the colored group, that is a face_clone of the "holes".
Don't know yet how I am going to use it as a reference for what to delete, since the faces are inside an individual group.
Tried exploding it but the reference to the faces gets deleted.This could take a while to fix...
-
I think you need to take a step back on this face with holes issue...
If the originally selected face has holes then your cloned face can too...
You make a new group of the selected group/instance and explode it [recursively till it's all raw geometry].
You replicate the edges from the cloned face, inside this new group.
You .intersect_with() everything inside this new group so all edges get split etc.
You then test every edge in this group and if it fails it's collected and later the collection is erased.
The test for the edge needs to look at its start/end vertices positions and use face.classify_point(pt) - where the face tested is the originally selected face - you need to make several tests on each point as 'on face and not in hole', 'on edge', 'on vertex' etc might all count'... but 'off face' or 'in hole' won't.
If an edge has one or two 'on face and not in hole' that edge passed.
If an edge has one 'off face' or 'in hole' it fails.
If an edge has two 'on edge' or 'on vertex' hits then it might be either on OR off the original face - it's on the perimeter of the original face - it could be spanning a convex corner and by 'on' but it could be spanning a concave corner and be 'off'... so to test for this you then offset the start point towards the end point to find the midpoint of the edge mid=edge.start.position.offset(edge.line[1],edge.length/2) - now test that 'mid' point and if theta point returns 'true' for 'on face and not in hole' or 'on edge' then we know that that edge passes as its either a perimeter edge OR spanning a convex corner so it's 'on-face', but if it fails it's across a concave corner and it's listed for erasing later...
Set your tests up methodically and you should end up with a set of edges to go - the unwanted faces will go with them... -
@unknownuser said:
If the originally selected face has holes then your cloned face can too...
I hope the picture from last post did not make it look like I was having problem with the face.clone? It's the colored face(cutting comp) that is not getting holes, when totaly covering the holes. I provide another (more illustrating) picture.
@unknownuser said:
offset the start point towards the end point to find the midpoint of the edge mid=edge.start.position.offset(edge.line[1],edge.length/2) - now test that 'mid' point and if theta point returns 'true' for 'on face and not in hole' or 'on edge' then we know that that edge passes as its either a perimeter edge OR spanning a convex corner so it's 'on-face', but if it fails it's across a concave corner and it's listed for erasing later...
That is pretty clever That will help to get rid of edges in holes.
@unknownuser said:
the unwanted faces will go with them...
Probably not every time? Look at the picture, the big hole has no edges in it. Faces without edges in them will not get erased.
Thank you for the help, TIG. I will try to get this working.
-
Another question TIG, about start point offset to mid. I put you formula iterating through edges. And yes, I see the additional midpoints being counted(using puts).
Question is. Can points be used for erasing edges that way? Must not there be a vertice on the edge at that position to be able to delete the edge? I'm using If edge used by?
But the edge is not using that offset point, it's just a dot in space. Am I getting it wrong?I suppose I could use edge.split at that mid.point. But that would DOUBLE the vertices and have splits in the middle of every edge in the component! Could kill Sketchup, having patterns like Earthmover was showing?
@unknownuser said:
I think you need to take a step back on this face with holes issue...
Yeah, getting crazy about it...
-
NO !
Each tested pair of points for an edge just tells us that the related edge must go if they fail on some grounds, or if it the result is just 'iffy' then re-test for the midpoint and if that fails then off the edge goes into theedges2go
array; and when all edges are examined fully you doedges2go.flatten!
to remove duplicates [just in case there are any! there shouldn't be] and then useedges2go[0].parent.entities.erase_entities(edges2go)
... -
@unknownuser said:
NO !
Clear enough
Ok, I will continue with this method. You showed me some new moves there I haven't tried.
-
Also why not look at it this alternative way?
You use the original selected group; or if it's an instance then add that to a new group and immediately explode the instance. Now either way you now have a group to use.
Usegroup.entities.intersect_with()
using the the group.entities for the results, with a new transformations [0,0,0], and the object to intersect being((face.edges)+face)
.
Now test all of the group.entities edges for being on the originally selected 'face' as already outlined...
Any lines not on the face get erased.
Now it's possible that some faces in the group might still remain over holes in the face...
To find and remove those examine each face within group.entities [let's called each 'tface'].
Test the following pointpt=tface.bounds.center.project_to_plane(face.plane)
for being on the 'face' [but not in a hole!]... It will fail if it's one of the faces over a 'hole' in 'face' - if so add the tface to a 'faces2go' array.
When all faces are tested usefaces2go[0].parent.entities.erase_entities(faces2go)
.
Now the last step is to check for any un-faced edges left after these unwanted faces were removed...group.entities.to_a.each{|e|e.erase! if e.class==Sketchup::Edge and not e.faces[1]}
...
NOW we should have things sorted ??? -
I have to call it a day. Been at it since morning without any results. Your new approach here give me hope.
I will sleep on it and try this tomorrow.
Thanks for helping me out TIG.
-
My alternative way is a bit simpler.
Here it is reiterated.
Select face and group or instance.
Run tool.
Tool sorts out the parts: one face and one group/instance.
If it's an instance it's grouped and exploded and that group is used.
Now you
tr=Geom::Transformation.new() group.entities.intersect_with(true,tr,group.entities,tr,true,(face.edges+[face]))
You then then collect all of the edges in the group.
Make an array -edges2go=[]
Test each edge in turn.
pts=edge.start.position
then
pte=edge.end.position
againstface.classify_point(pts)
etc
If one point is 'on the face' [and not in a hole] AND the other point is 'on the face' [and not in a hole] OR it's on a face's edge OR on a vertex then that edge is OK.
If both of these points are NOT 'on the face' [and not in a hole] AND NOT on a face's edge AND NOT on a face's vertex, then it's
edges2go << edge
.
If both points are on one of the face's edges or vertices then it could be either 'on' or 'off' face; so we must test the edge's midpoint (mid=pts.offset(edge.line[1], edge.length/2)
) to see if that's 'on the face' [not in a hole] OR on a face's edge OR on a vertex - IF it is any of these then it's OK as it's spanning a convex corner and is all 'on face', otherwise it's off toedges2go << edge
again, as it's spanning a concave corner - either within a 'hole' or an internal L-shape and falls outside of the face !
You then erase all of these unwanted edges [any connected faces go with them] with
group.entities.erase_entities(ents2go)
There should be no 'stray lines' left by this method and this allows loose unfaced edges to be in the group and remain [trimmed to the face edges if needed]...This simpler idea can then be applied to the main hatching tool tool.
We get the hatch/crosshatch parameters.
We iterate through selected faces in turn.
A new 'hatch' group is made that will become bigger than each face bounds... lines are added to form the hatch/crosshatch [in the plane of the face], all of these lines are then intersected_with the 'face'. Each of the edge's two points are again tested with face.classify_point() [and midpoint if questionable] to make an array of unwanted ones to remove. -
Wow, TIG! Will be interesting to test your new approach.
BTW:
@unknownuser said:
tr=Geom::Transformation.new()
group.entities.intersect_with(true,tr,group.entities,tr,true,(face.edges+[face]))
You then then collect all of the edges in the group.
Make an array - edges2go=[]
Test each edge in turn.
pts=edge.start.position
then
pte=edge.end.position
against face.classify_point(pts) etcIsent this what I'm doing already? Except (face.edges+[face)] is a group(gp3) for me?
Or did I misunderstand you? Anyway, that may not be of relevance for fixing the problem.I think the main problem is that, after the collection of points "outside" face I have been using if edge.used_by? point to select and erase the edges. Passing on the point as argument. (In reality point gets converted to vertices). That way I can never erase an edge if it's not used by "something".
I guess your way is to tell Sketchup. If point is on edge? Put that edge in the "erase" array. Is that correct?
This all have to be done in an iterator, right? With some conditionals inside the iterator. I spent all day yesterday to find suitable API methods to fit the need, but really need some IF, NOT and OR statements? Or am I wrong here in my assumption?
I guess the iterator will be faster if the statements are made outside..I will try those things and pt=tface.bounds.center.project_to_plane(face.plane) and the edge.midpoint test as well.
Again, thanks a lot!
-
Wait. I think I got it backwards, TIG..
I was looking in the API, and the closest thing to compare an point on edge was, point3d on_line.
What I could see.Then realized, maybe you meant that there should be only 1 iteration, in edge.array?
Iterate through edge.array, do the tests. If true or false(depending on the test) then edges2go << edge ?
After that, erase arrays entitiesedges2go?
Is it something like that what you had in mind, TIG?
-
NO, NO, NO!
When you doface.classify_point(pt)
you get ONE of a list of possible results:
http://code.google.com/apis/sketchup/docs/ourdoc/face.html#classify_point
The list is0: Sketchup::Face::PointUnknown (indicates an error),
1: Sketchup::Face::PointInside (point is on the face, not in a hole),
2: Sketchup::Face::PointOnVertex (point touches a vertex),
4: Sketchup::Face::PointOnEdge (point is on an edge),
16: Sketchup::Face::PointOutside (point outside the face or in a hole),
32: Sketchup::Face::PointNotOnPlane (point off the face's plane). So if the result of either of thevertex.position
points isSketchup::Face::PointInside
then it's OK.
If either areSketchup::Face::PointOutside
it has to GO!
If both areSketchup::Face::PointOnVertex
ORSketchup::Face::PointOnEdge
then it might be OK - you test for the midpoint etc and if it'sSketchup::Face::PointOutside
it has to GO!...
Iterate the edges just once and collect all that fail; then erase them en mass... -
@tig said:
NO, NO, NO!
Tough on your students as all great masters are! I'm just picturing the huge face palm from a steamed but brilliant TIG as he has to constantly communicate with us "less brained" folk. Seriously, though your patience and constant help is much appreciated. I've been trying to follow both threads with you and Joel going back and forth and I'm starting to pick up a little of what is going on, although it's still all over my head.
-
I need my dinner and a drink!
-
@unknownuser said:
NO, NO, NO!
I think I explained the question poorly. SWEnglish at it's worst. Haven't you seen the Swedish chef in the Muppet show?
I know about http://code.google.com/apis/sketchup/do%20...%20sify_point Im already using it in the code
The question was. Only 1 iteration?
If you have looked at my code you see that I first collect edge.start, edge.end and edges. THEN I collect the points outside the face. After that I collect edges that are connected to those vertices. So all in all 3 iterators for just 1 purpose.
What I meant about point3d on_line, was that WHEN I was looking at that method in the API I realized I should use 1 iterator, NOT that I should use point 3d on_line. That's a whole different matter
Earthmover wrote:
@unknownuser said:
Seriously, though your patience and constant help is much appreciated.
You bet! I'm deeply greatful.
Therefore Here Ya go!
-
No... try to simplify your code.
I'm trying to suggest a streamlined approach, that both faster and 'easier to get your head around'.
After the intersecting etc... edges will be split by every edge of the face and then these possibly split edges will either fall 'on' the face, 'off' the face, OR with both vertices on the face's perimeters...
Collect all of the edges inside the group.
Check each edge in turn, looking at its two vertices' positions and seeing where they are 'on' the face.
Some edges are clearly 'on' - some are clearly 'off'... from testing a vertex.position in the face.classy_point() method... There are several possible results but careful interpretation will prove VERY useful...
If there are questionable edges [with both vertices on the face's edges or face's vertices] you can check if that edge is 'spanning' a convex or concave corner. If it's 'concave' the midpoint of the edge is not on the face so it has to be erased later on...
So just do the tests as I described... and make an array of 'edge-failures'.
Once you've been through all of the edges in the group you can then erase the array of edge-failures 'en mass'.
Done - the group is trimmed to every perimeter of the face - including its 'holes'.
Because faces need edges they'll also go with the 'removed edges'.
this is much simpler... -
@unknownuser said:
I'm trying to suggest a streamlined approach
I will try to do my best. I think I know now what you mean. If I do it right, I think we will see some speed improvements as well.
Finally time to do some coding, been preoccupied with bunch of boring things today.
Off to work
-
Well I think we are back to par with this method!
And it seams a whole lot faster. Haven't tried on heavy geometry. But It really feels faster.
It seams to erase edges as it should be. And on the + side edges inside holes get's erased, which is really good.
Actually point outside is all you need. I don't think there is any need to test on every scenario?
I've set up the iterator like this. Where gp2edge is edge.array and comparefaces are the face to be used in classify point.
Names will get shorter later on. I think it's good when workin on the code to have explaining names..gp2edge.to_a.each{|edge| comparefaces.to_a.each{|face| if face.classify_point(edge.start)==Sketchup;;Face;;PointOutside and face.classify_point(edge.end)==Sketchup;;Face;;PointOutside gp2ptogo << edge end if face.classify_point(edge.start.position.offset(edge.line[1], edge.length/2))==Sketchup;;Face;;PointOutside gp2ptogo << edge end } }
Now if we could just get rid of the faces in the holes. I'm gonna try pt=tface.bounds.center.project_to_plane(face.plane) and see what happends....
Advertisement