문제

I'm trying to find an algorithm to cut a 3D object using two (or more) section planes. The object should only be cut where both section planes are cutting. So consider the following abcd rectangle that is intersected by two section planes: s0 and s1; s1 cuts towards the right and s0 cuts towards the top. What I would like is to have the resulting ajikcd shape.

.        |s1
. a______j_________b  ^
. |      |         |  |
. |- - - i - - - - |k- - s0
. |      |         |  
. d----------------c
.        |->

This is a quite simplistic example but I hope it will make it clear what I'm trying to accomplish. In addition, this should be done in 3D.

Does anybody know of any library that does that, or an algorithm to do it? This seems like an non-trivial problem that someone must have solved before me! :)

I must add that I know how to do the basics (intersection of plane with face/plane/edge). What I can't see is whether there is a smart way to solve all possible cases (in this one, two faces must be added, but in some other only one face might be created, etc.), or if you should handle them separately.

Another thing I should add is that I'm not concerned about the rendering part, I know how to do it with OpenGL with clipping planes. What I want is to be able to compute the new topology of the object.

도움이 되었습니까?

해결책

I think this can be fairly easily solved by slicing the object up, removing the unwanted section, and then gluing the leftover pieces back together by merging faces.

Assuming you are modelling your object as a fully-linked graph

  • A list of vertices, each with a list of edges
  • A list of edges, each with references to two vertices and two faces
  • A list of faces, each with a list of edges

As long as you are careful in maintaining and manipulating this graph, it holds all the information needed to quickly cut and merge your objects.

You can use the algorithm described in this answer to compute the new face resulting from the cut.

So: your inputs to the algorithm are a list of cutting planes and a list of objects - initially there is only one. For each cutting plane, slice each object in the list object into two and put them back into the list. The two faces that are added (one on each of the new objects) should keep a reference to the cutting plane that produced them. For faces that are cut in half by a plane, remember that the two new faces produced should inherit this reference if it exists. The new objects should keep a record of which side of the plane they lie (just a boolean meaning 'keep' or 'discard')- these records should also be maintained as the objects are further subdivided.

Once all the cuts have been made, you'll have a list of objects, each of which has a list of records detailing on which side of the cutting planes they lie. Find the objects where all of those records are 'discard' and throw them away.

We now have to stick the objects back together.

Start by trivially merging the object graphs - simply combine all of the vertex, edge and face lists into one object. We now examine the two faces that were created by the same cutting plane:

  • If the two faces are identical (i.e.: they share the same set of vertices) then both faces and all associated edges can be removed.
  • If the vertex set of one face is larger than the other, then remove the smaller face and all shared edges.

You should now have a merged object, but with some extraneous vertices. Simple iterate through the vertices and remove those that only have two associated edges.

Here's an example of how the cutting would work:

      :
a---1-:---b
|     :   |
2   X :   3
|     :   |
|     :   |
c---4-:---d
      :
      :s 

We start with one object (? denotes some edge or face not shown):

verts:
  a:1,2,?
  b:1,3,?
  c:2,4,?
  d:3,4,?
edges:
  1:a,b X,?
  2:a,c X,?
  3:b,d X,?
  4:c,d X,?
faces:
  X:1,2,3,4
  ?:...

When we cut with the plane s, we end up with two objects:

a--1--e-7-b
|     |   |
2  X  5 Y 3
|     6   |
|     |   |
c--4--f-8-d

verts:            verts:         
  a:1,2,?           e:1,5,6,7    
  e:1,5,6,7         b:3,7,?        
  c:2,4,?           d:3,8,?        
  f:4,5,6,8         f:4,5,6,8    
edges:            edges:         
  1:a,e X,?         3:b,d Y,?    
  2:a,c X,?         6:e,f Y,W    
  4:c,f X,?         7:e,b Y,?    
  5:e,f X,V         8:f,d Y,?    
faces:            faces:         
  X:1,2,3,4         Y:3,6,7,8    
  V:5,...           W:6,...      
  ?:...             ?:...

We've added vertices e and f, edges 5 and 6, and faces V and W. Note that edges 5 and 6 are distinct objects, sharing the same vertices but between different faces.

When we come to merge these two objects back together, we first trivially merge the two object graphs:

verts:
  a:1,2,?
  b:3,7,?        
  c:2,4,?
  d:3,8,?
  e:1,5,6,7        
  f:4,5,6,8  
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,d Y,?    
  4:c,f X,?         
  5:e,f X,V         
  6:e,f Y,W    
  7:e,b Y,?
  8:f,d Y,?    
faces:
  X:1,2,3,4
  Y:3,6,7,8    
  V:5,...           
  W:6,...      
  ?:...

We can see that faces V and W were produced by the same cutting plane and have the same vertex set, and so they can be removed along with the associated edges. The two non-removed faces associated with a pair of coincident edges are merged.

a--1--e-7-b
|         |
2  X      3
|         |
|         |
c--4--f-8-d

verts:
  a:1,2,?
  b:3,7,?        
  c:2,4,?
  d:3,8,?
  e:1,7        
  f:4,8  
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,d X,?    
  4:c,f X,?    
  7:e,b X,?
  8:f,d X,?    
faces:
  X:1,2,3,4,7,8
  ?:...

We can then remove the vertices with only two associated edges, and merge those edges:

verts:
  a:1,2,?
  b:1,3,?        
  c:2,4,?
  d:3,8,?
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,d Y,?    
  4:c,d X,?
faces:
  X:1,2,3,4
  Y:3,6,7,8  
  ?:...

What about merging these objects?

a--1--e
|     5   
2  X  g-3-b
|     6   |
|     9 Y 7
c--4--f-8-d

verts:            verts:         
  a:1,2,?           g:3,5,6,?    
  e:1,5,?           b:3,7,?        
  c:2,4,?           d:7,8,?        
  f:4,6,8,9,?       f:4,6,8,9,?
edges:            edges:         
  1:a,e X,?         3:b,g Y,?    
  2:a,c X,?         9:f,g Y,W    
  4:c,f X,?         7:b,d Y,?    
  5:e,g X,V,?       8:f,d Y,?    
  6:f,g X,V
faces:            faces:         
  X:1,2,4,5,6       Y:3,7,8,9
  V:5,6,...         W:9,...      
  ?:...             ?:...

We merge:

verts:
  a:1,2,?    
  b:3,7,?               
  e:1,5,?           
  c:2,4,?           
  d:7,8,?        
  f:4,6,8,9,?         
  g:3,5,6,9,?    
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,g Y,?    
  4:c,f X,?         
  5:e,g X,V,?         
  6:f,g X,V
  7:b,d Y,?    
  8:f,d Y,?    
  9:f,g Y,W    
faces:
  X:1,2,4,5,6
  Y:3,6,7,8    
  V:5,6,...
  W:9,...
  ?:...

and examine faces V and W, as they have been created by the same cut plane. This time their vertex sets are different. Remove the smaller face. In the two faces, find the edges that have the same vertices and remove them:

a--1--e
|     5   
2  X  g-3-b
|         |
|         7
c--4--f-8-d

verts:
  a:1,2,?    
  b:3,7,?               
  e:1,5,?           
  c:2,4,?           
  d:7,8,?        
  f:4,8         
  g:3,5,?    
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,g X,?    
  4:c,f X,?         
  5:e,g X,V,?
  7:b,d X,?    
  8:f,d X,?
faces:
  X:1,2,3,4,5,7,8
  V:5,...
  ?:...

We can now remove the useless vertices with only two incident edges:

a--1--e
|     5   
2  X  g-3-b
|         |
|         7
c----4----d

verts:
  a:1,2,?    
  b:3,7,?               
  e:1,5,?           
  c:2,4,?           
  d:4,7,?   
  g:3,5,?    
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,g Y,?    
  4:c,d X,?         
  5:e,g X,?
  7:b,d X,?
faces:
  X:1,2,3,4,5,7
  V:5,...
  ?:...

Phew! Hope this helps...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top