Intersection of two section planes - geometry

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...

Related

how to calculate relative pose given two 4x4 affine matrix

I have two 4x4 affine matrix, A and B. They represent the pose of two objects in the world coordinate system.
How could I calculate their relative pose via matrix multiplication ? (Actually, I want to know the position(x_A,y_A) in the coordinate system of object B)
I've tried with relative pose = A * B^-1
relative_pose = torch.multiply(A, torch.inverse(B)).
However, the relative translation is way too big. (A and B are pretty close to each other, while they are far away from origin point in world coordinate.)
test data for pytorch:
import torch
A = torch.tensor([[-9.3793e-01, -3.4481e-01, -3.7340e-02, -4.6983e+03],
[ 3.4241e-01, -9.3773e-01, 5.8526e-02, 1.0980e+04],
[-5.5195e-02, 4.2108e-02, 9.9759e-01, -2.3445e+01],
[ 0.0000e+00, 0.0000e+00, 0.0000e+00, 1.0000e+00]])
B = torch.tensor([[-9.7592e-01, -2.1022e-01, -5.8136e-02, -4.6956e+03],
[ 2.0836e-01, -9.7737e-01, 3.6429e-02, 1.0979e+04],
[-6.4478e-02, 2.3438e-02, 9.9764e-01, -2.3251e+01],
[ 0.0000e+00, 0.0000e+00, 0.0000e+00, 1.0000e+00]])
So I assume you are using solid transformation matrices M in homogeneous coordinates, in other words 4x4 matrices containing a 3x3 rotation matrix R, a 3x1 translation vector T and a [0,0,0,1] homogeneous "padding" row vector. And you want to find the transformation to go from one pose to the other (I don't know how to write matrices by block, but that would be something like (R | T \\ 0 | 1)
Then I think your formula is wrong : if Y_1 = M_1 X and Y_2 = M_2 X, then you have Y_2 = M_2 M_1^-1 X, and your relative pose matrix is M_rel = M_2 M_1^-1
So you need to invert your solid transformation matrix M_1 = (R_1 | T_1 \\ 0 | 1)
If you write the equations, and if we note P = R_1^-1, then you'll find that M_1^-1 = (P | -PT \\ 0 | 1)
The math solution of #trialNerror is totally right. Here is a well structed answer about calculating inverse of affine matrix
I made a mistake in pytorch. The
torch.multiply offers element-wise multiplication. For multipying matrices, man shoud use torch.mm().
In my case with batch as extra dimension, the code should be like this
relative_pose = torch.inverse(A).bmm(B)

transformation of evenly spaced rectangular set of point

I have a set of evenly spaced point that forms a rectangle (sorry for the bad drawing, imagine all points are evenly spaced), and applying an angle, i want to go from left picture to right picture. The only point that does NOT move are the bottom left and the top right.
I guess i can deduce new locations of each point using tangent to get dx and dy. But i am not sur that i will end up with exactly what i want. And there may be a more elegent transformation to apply on each point ?
So we want to preserve two opposite vertices of rectangle and diagonal between them.
Let half-width of rectangle is w, half-height h, circle radius r. Let coordinate origin is at circle center.
Angle between diagonal and OX is
theta = atan(h/w)
After transformation angle between diagonal and low edge of new rectangle is
fi = alpha + theta
So we can find half-width of new rectangle
nw = r * cos(fi)
And coordinates of shifted vertex are
2*nw*cos(alpha) - w, -h - 2*nw*sin(alpha)
We want to find affine tranformation M that transform two vertices to the same points and the third vertex into coordinates above
|-w w w| |-w w 2*nw*cos(alpha) - w |
M * |-h h -h| = |-h h -h - 2*nw*sin(alpha)|
|1 1 1| |1 1 1|
To find M, we make inversion of the left matrix and multiply both sides by this inverse.
M = |nw*cos(alpha)/w w/h - nw*cos(alpha)/h 0|
|-nw*sin(alpha)/w 1 + nw*sin(alpha)/h 0|
|0 0 1|
Now we can transform all coordinates with this matrix and get rotated rectangle.
Example of coordinate transformation from my Delphi program generating picture below:
nX := Round(cx + x * cos(alpha)*nw/w + y * (w/h - cos(alpha)*nw / h));
nY := Round(cy - x * nw/w*sin(alpha) + y * (1 + nw/h * sin(alpha)));

Convert wavefront obj mesh to custom mesh representation

Code that I'm trying to understand represents meshes using this structure:
struct vertex
{
float v[3]; // vertex coords
float t[3]; // texture coords
float n[3]; // normals
};
typedef unsigned face[3];
struct mesh
{
vector<vertex> vn;
vector<face> fn;
};
Then, I wrote a quick parser for wavefront obj mesh format. This is the sample mesh that I'm loading. It only has v, vn, vt, f elements. The most important part of this sample mesh is that it has all faces with matching indices for v/vt/vn and I can load it easily into my struct mesh specified above:
f 2/2/2 2/2/2 1/1/1
f 1/1/1 2/2/2 3/3/3
...
Now, I'm trying to figure out how to load an obj mesh that does not have these v/vt/vn matching. This second sample mesh supposedly should represent identical shape to the one specified above. As you can see faces do not always have matching v/vt/vn triplets, like here:
f 3/3/3 1/1/1 2/2/2
f 2/2/2 1/1/1 6/12/6
...
f 3/15/3 10/13/10 9/14/9
...
It would be ok if the triplets were unique (e.g. always 3/15/3), but there are also different triplets for v=3: 3/3/3.
If I ignore for now /vt/vn part I can still load the shape but I loose normals/texture coords and I do not get correct visual representation of the shape (looses textures and light reflection from the shape).
What should I do to load that mesh properly into my internal representation? Should I just create two vertices with identical coords where one vertex would have vn=3,vt=3 and the other one would have vn=15,vt=3?..
(disclaimer: my experience in 3d graphics and meshes is about a day and a half)

how to extend vectors dimensions with POS tagging?

How do I extend vector's dimensions with part-of-speech information to embed lets say 50 features of POS, tagging to 300 features of vectors finally ended up with 350?

What do the BILOU tags mean in Named Entity Recognition?

Title pretty much sums up the question. I've noticed that in some papers people have referred to a BILOU encoding scheme for NER as opposed to the typical BIO tagging scheme (Such as this paper by Ratinov and Roth in 2009 http://cogcomp.cs.illinois.edu/page/publication_view/199)
From working with the 2003 CoNLL data I know that
B stands for 'beginning' (signifies beginning of an NE)
I stands for 'inside' (signifies that the word is inside an NE)
O stands for 'outside' (signifies that the word is just a regular word outside of an NE)
While I've been told that the words in BILOU stand for
B - 'beginning'
I - 'inside'
L - 'last'
O - 'outside'
U - 'unit'
I've also seen people reference another tag
E - 'end', use it concurrently with the 'last' tag
S - 'singleton', use it concurrently with the 'unit' tag
I'm pretty new to the NER literature, but I've been unable to find something clearly explaining these tags. My questions in particular relates to what the difference between 'last' and 'end' tags are, and what 'unit' tag stands for.
Based on an issue and a patch in Clear TK, it seems like BILOU stands for "Beginning, Inside and Last tokens of multi-token chunks, Unit-length chunks and Outside" (emphasis added). For instance, the chunking denoted by brackets
(foo foo foo) (bar) no no no (bar bar)
can be encoded with BILOU as
B-foo, I-foo, L-foo, U-bar, O, O, O, B-bar, L-bar
I would like to add some experience comparing BIO and BILOU schemes. My experiment was on one dataset only and may not be representative.
My dataset contains around 35 thousand short utterances (2-10 tokens) and are annotated using 11 different tags. In other words, there are 11 named entities.
The features used include the word, left and right 2-grams, 1-5 character ngrams (except middle ones), shape features and so on. Few entities are gazetteer backed as well.
I shuffled the dataset and split it into 80/20 parts: training and testing. This process was repeated 5 times and for each entity I recorded Precision, Recall and F1-measure. The performance was measured at entity level, not at token level as in Ratinov & Roth, 2009 paper.
The software I used to train a model is CRFSuite. I used L-BFGS solver with c1=0 and c2=1.
First of all, the test results compared for the 5 folds are very similar. This means there is little of variability from run to run, which is good. Second, BIO scheme performed very similarly as BILOU scheme. If there is any significant difference, perhaps it is at the third or fourth digit after period in Precision, Recall and F1-measures.
Conclusion: In my experiment BILOU scheme is not better (but also not worse) than the BIO scheme.
B = Beginning
I/M = Inside / Middle
L/E = Last / End
O = Outside
U/W/S = Unit-length / Whole / Singleton
So BILOU is the same with IOBES and BMEWO.
Cho et al. compares performance of different IO, IB, IE, IOB, IOBES, etc. annotation variants. https://www.academia.edu/12852833/Named_entity_recognition_with_multiple_segment_representations
There is also BMEWO+, which put more information about surrounding word class to Outside tokens (thus "O plus"). See details here https://lingpipe-blog.com/2009/10/14/coding-chunkers-as-taggers-io-bio-bmewo-and-bmewo/
This just gives more context to your tags saying which part of the entity.
BILOU Method/Schema
| ------|--------------------|
| BEGIN | The first token |
| ------|--------------------|
| IN | An inner token |
| ------|--------------------|
| LAST | The final token |
| ------|--------------------|
| Unit | A single-token |
| ------|--------------------|
| Out | A non-entity token |
| ------|--------------------|
BIOES
A more sophisticated annotation method distinguishes between the end of a named entity and single entities. This method is called BIOES for Begin, Inside, Outside, End, Single.
IOB (e.g. CoNLL 2003)
IOB (or BIO) stands for Begin, Inside and Outside. Words tagged with O are outside of named entities
for more detailed information Please go through the below link
URL : https://en.wikipedia.org/wiki/Inside%E2%80%93outside%E2%80%93beginning_(tagging)
URL :https://towardsdatascience.com/deep-learning-for-ner-1-public-datasets-and-annotation-methods-8b1ad5e98caf
B - 'begin'
I - 'inside'
L - 'last'
O - 'outside/other'
U - 'unigram'
BIO is the same as BILOU except for the following points:
In BILOU, the last I tag in a particular I "cluster" would be converted to L.
Eg.
BIO - B-foo, I-foo, I-foo, O, O, O, B-bar, I-bar
BILOU - B-foo, I-foo, L-foo, O, O, O, B-bar, L-bar
In BILOU, any standalone tag is converted to a U tag.
Eg.
BIO - B-foo, O, O, O, B-bar
BILOU - U-foo, O, O, O, U-bar
Following is a set of same tags represented in both BIO and BILOU notations:
BIO - B-foo, I-foo, I-foo, O, O, B-bar, I-bar, O, B-bar, O
BILOU - B-foo, I-foo, L-foo, O, O, B-bar, L-bar, O, U-bar, O

Resources