Bisector plane between two panes? C# - c#

I do not know how to approach this problem as I am using API that has Plane data structure that is basically origin point, x y and z vectors that define a plane.
If I have two planes, how can I find bisector plane?
Is there a mathematical description for such plane.
Geometrically I would approach this problem by calculating intersection line between planes and then no idea how to define a point for direction that plane.
Any help would be much appreciated.
Before I tried something like this, and this get what I want, but I am wondering if there is a solution without doing intersections:
public static Plane BisectorPlane(Plane a, Plane b)
{
Rhino.Geometry.Intersect.Intersection.PlanePlane(a, b, out Line lnA);
a.Translate(a.ZAxis);
b.Translate(b.ZAxis);
Rhino.Geometry.Intersect.Intersection.PlanePlane(a, b, out Line lnB);
return new Plane( lnA.From,lnA.To,lnB.PointAt(0.5));
}
I am wondering if it is possible to solve this is not geometrically (calculating intersections) but mathematically.

You already have got line of intersection. Now choose any point P at this line to make base point.
Get direction vector for this line (dL)
Get sum of unit normals for given planes S. This is vector lying in bisector plane and perpendicular to intersection line
S = (a.normal + b.normal)
Now calculate vector product of dL and S to get normal
BisectorN = dL x S
And normalize it (make unit length dividing by its length) if needed
bN = BisectorN.Normalize
Base point P and normal bN define bisector plane.

I tried your approach and it gives bisector plane. But the problem is that planes shifts as it is constructed from origin and normal, not from origin and two x and y axis:
Point3d origin = lnA.PointAt(0.5);
Vector3d S = a.Normal + b.Normal;
Vector3d dL = Vector3d.Subtract((Vector3d)lnA.From, (Vector3d)lnA.To);
Vector3d BisectorN = Vector3d.CrossProduct(dL,S);
BisectorN.Unitize();
return new Plane(origin, BisectorN);

Related

How to find the area that two triangles are in contact

Given the positions of the vertices, and the surface normals. How can I calculate the area(which may be 0) that the 2 triangles are in contact? These triangles are also in 3D space so if they aren't lined up properly, just jammed into each other, the contact area should be 0.
(In C#)
This is not a trivial problem, so let's break it down into steps.
Check if the two triangles are coplanar, otherwise the area is 0.
Project the triangles onto a 2D surface
Calculate the intersection polygon
Calculate the area
1. Checking for coplanarity
For the two triangles to be coplanar, all vertices of one triangle must lie in the plane determined by the other one.
Using the algorithm described here we can check for every vertex whether that is the case, but due to the fact that floating point numbers are not perfectly precise, you will need to define some error theshold to determine what still counts as coplanar.
Assuming va and vb are the vectors of the triangles A and B respectively, the code could look something like this.
(Note: I have never worked with Unity and am writing all of the code from memory, so please excuse if it isn't 100% correct).
public static bool AreTrianglesCoplanar(Vector3[] va, Vector3[] vb) {
// make sure these are actually triangles
Debug.Assert(va.Length == 3);
Debug.Assert(vb.Length == 3);
// calculate the (scaled) normal of triangle A
var normal = Vector3.Cross(va[1] - va[0], va[2] - va[0]);
// iterate all vertices of triangle B
for(var vertex in vb) {
// calculate the dot product between the normal and the vector va[0] --> vertex
// the dot product will be 0 (or very small) if the angle between these vectors
// is a right angle (90°)
float dot = Vector3.Dot(normal, vertex - va[0]).
// the error threshold
const float epsilon = 0.001f;
// if the dot product is above the threshold, the vertex lies outside the plane
// in that case the two triangles are not coplanar
if(Math.Abs(dot) > epsilon)
return false;
}
return true;
}
2. Projecting the triangles into 2D space
We now know that all six vertices are in the same 2D plane embedded into 3D space, but all of our vertex coordinates are still three-dimensional. So the next step would be to project our points into a 2D coordinate system, such that their relative position is preserved.
This answer explains the math pretty well.
First, we need to find a set of three vectors forming an orthonormal basis (they must be orthoginal to each other and of length 1).
One of them is just the plane's normal vector, so we need two more vectors that are orthogonal to the first, and also orthogonal to each other.
By definition, all vectors in the plane defined by our triangles are orthogonal to the normal vector, so we can just pick one (for example the vector from va[0] to va[1]) and normalize it.
The third vector has to be orthogonal to both of the others, we can find such a vector by taking the cross product of the previous two.
We also need to choose a point in the plane as our origin point, for example va[0].
With all of these parameters, and using the formula from the linked amswer, we can determine our new projected (x, y) coordinates (t_1 and t_2 from the other answer). Note that -- because all of our points lie in the plane defining that normal vector -- the third coordinate (called s in the other answer) will always be (close to) zero.
public static void ProjectTo2DPlane(
Vector3[] va, Vector3[] vb
out Vector2[] vaProjected, out Vector2[] vbProjecte
) {
// calculate the three coordinate system axes
var normal = Vector3.Cross(va[1] - va[0], va[2] - va[0]).normalized;
var e1 = Vector3.Normalize(va[1] - va[0]);
var e2 = Vector3.Cross(normal, e1);
// select an origin point
var origin = va[0];
// projection function we will apply to every vertex
Vector2 ProjectVertex(Vector3 vertex) {
float s = Dot(normal, vertex - origin);
float t1 = Dot(e1, vertex - origin);
float t2 = Dot(e2, vertex - origin);
// sanity check: this should be close to zero
// (otherwise the point is outside the plane)
Debug.Assert(Math.Abs(s) < 0.001);
return new Vector2(t1, t2);
}
// project the vertices using Linq
vaProjected = va.Select(ProjectVertex).ToArray();
vbProjected = vb.Select(ProjectVertex).ToArray();
}
Sanity check:
The vertex va[0] should be projected to (0, 0).
The vertex va[1] should be projected to (*, 0), so somewhere on the new x axis.
3. / 4. Calculating the intersection area in 2D
This answer this answer mentions the algorithms necessary for the last step.
The Sutherland-Hodgman algorithm successively clips one triangles with each side of the other. The result of this will be either a triangle, a quadrilateral or an empty polygon.
Finally, the shoelace formula can be used to calculate the area of the resulting clipping polygon.
Bringing it all together
Assuming you implemented the two functions CalculateIntersecionPolygon and CalculatePolygonArea, the final intersection area could be calculated like this:
public static float CalculateIntersectionArea(Mesh triangleA, Mesh triangleB) {
var verticesA = triangleA.GetVertices();
var verticesB = triangleB.GetVertices();
if(!AreTrianglesCoplanar(verticesA, verticesB))
return 0f; // the triangles are not coplanar
ProjectTo2DPlane(verticesA, verticesB, out Vector2[] projectedA, out Vector2[] projectedB);
CalculateIntersecionPolygon(projectedA, projectedB, out List<Vector2> intersection);
if(intersection.Count == 0)
return 0f; // the triangles didn't overlap
return CalculatePolygonArea(intersection);
}

Determining the grids cut by a plane,formed from 3 vertices

I found out an equation of a plane,from three vertices.
Now,if I have a bounding box(i.e. a large cube),How can I determine the grid positions(small cubes),where the plane cuts the large cube.
I am currently following this approach:
For each small cube center, say(Xp, Yp, Zp), calculate perpendicular distance to the plane i.e., (aXp + bYp + c*Zp + d)/ (SquareRoot Of (a^2 + b^2 + c^2)). This should be less than or equal to (length of smallCube * SquareRoot(3))/2.
If this criteria,gets satisfied,then I assume my plane to cut the large cube at this small cube position.
a,b,c,d are coefficients of the plane,of the form ax+by+cz+d = 0.
I would be really glad,if someone can let me know,if I am doing something wrong (or) also,any other simple approach.
Seems you want to get a list of small cubes (grid voxels) intersected by given plane.
The simplest approach:
Find intersection of the plane with any cube edge. For example, intersection with vertical edge of AAB (X0,Z0 are constant) might be calculated by solving this equation for unknown Y:
aX0 + bY + c*Z0 + d = 0
and checking that Y is in cube range. Get small cube coordinates (0, ky=Floor(Y/VoxelSize), 0) and then check neighbor voxels in order (account for plane coefficients to check only real candidates).
candidates:
0,ky,0
1,ky,0
0,ky-1,0
0,ky+1,0
0,ky,1
There are more advanced methods to generate voxel sequence for ray case (both 2d and 3d) like Amanatides/Woo algorithm. Perhaps something similar exists also for plane voxelization
Here is AABB-plane intersection test code from this page (contains some explanations)
// Test if AABB b intersects plane p
int TestAABBPlane(AABB b, Plane p) {
// Convert AABB to center-extents representation
Point c = (b.max + b.min) * 0.5f; // Compute AABB center
Point e = b.max - c; // Compute positive extents
// Compute the projection interval radius of b onto L(t) = b.c + t * p.n
float r = e[0]*Abs(p.n[0]) + e[1]*Abs(p.n[1]) + e[2]*Abs(p.n[2]);
// Compute distance of box center from plane
float s = Dot(p.n, c) - p.d;
// Intersection occurs when distance s falls within [-r,+r] interval
return Abs(s) <= r;
}
Note that e and r remain the same for all cubes, so calculate them once and use later.

Function to generate flight trajectory (list of 3D points, lat, lon, alt)

I am looking to generate some 3D trajectory data for an aircraft simulation.
The idea is that the aircraft takes off at some location x and continues to ascend at some average ascent velocity a_v and angle a_theta until it reaches a maximum altitude m_a. The aircraft would then continue at its m_a until it reaches a certain distance d_d from its destination, at which point it will begin its descent at some angle d_theta with an average descent velocity of d_v. Finally, the aircraft lands at destination y.
I would like the function to return a list of 3D points.
I am looking to implement this in either Python (preferred) or C#.
For illustration purposes:
Does anyone know how I can achieve this? Is there perhaps some open source project which does this? I have been looking for a while now, but have not found anything.
I recommend you to solve the problem in 2 independent steps so that the airplane does not pass through the ground :
Calculate the path on the surface of a sphere.
Interpolate the height along this path.
For 1. you can use the spherical interpolation techniques on Quaternions.
Quaternion slerp(Quaternion v0, Quaternion v1, double t) {
// Only unit quaternions are valid rotations.
// Normalize to avoid undefined behavior.
v0.normalize();
v1.normalize();
// Compute the cosine of the angle between the two vectors.
double dot = dot_product(v0, v1);
const double DOT_THRESHOLD = 0.9995;
if (fabs(dot) > DOT_THRESHOLD) {
// If the inputs are too close for comfort, linearly interpolate
// and normalize the result.
Quaternion result = v0 + t*(v1 – v0);
result.normalize();
return result;
}
// If the dot product is negative, the quaternions
// have opposite handed-ness and slerp won't take
// the shorter path. Fix by reversing one quaternion.
if (dot < 0.0f) {
v1 = -v1;
dot = -dot;
}
Clamp(dot, -1, 1); // Robustness: Stay within domain of acos()
double theta_0 = acos(dot); // theta_0 = angle between input vectors
double theta = theta_0*t; // theta = angle between v0 and result
Quaternion v2 = v1 – v0*dot;
v2.normalize(); // { v0, v2 } is now an orthonormal basis
return v0*cos(theta) + v2*sin(theta);
}
You didn't write any code, so I won't write any either. Python with math package is more than enough to solve this problem.
Required steps:
The plane should fly on a great circle. This means you only need one distance to describe X and Y.
You could place the origin at X and specify Y with a latitude.
Calculate the tangent of the Earth at X, and rotate by a_theta. Find the point where it reaches m_a altitude.
Calculate the tangent of the Earth at Y, and rotate by d_theta. Find the point where it reaches m_a altitude.
Draw an arc between the two previous points, with a radius of EarthRadius + m_a
Every coordinate is known in the 2D of the great circle, you just need to rotate them back to 3D coordinates.
For a list of 3D points, you don't need either a_v, d_v or d_d.

Given 3 points, how do I calculate the normal vector?

Given three 3D points (A,B, & C) how do I calculate the normal vector? The three points define a plane and I want the vector perpendicular to this plane.
Can I get sample C# code that demonstrates this?
It depends on the order of the points. If the points are specified in a counter-clockwise order as seen from a direction opposing the normal, then it's simple to calculate:
Dir = (B - A) x (C - A)
Norm = Dir / len(Dir)
where x is the cross product.
If you're using OpenTK or XNA (have access to the Vector3 class), then it's simply a matter of:
class Triangle {
Vector3 a, b, c;
public Vector3 Normal {
get {
var dir = Vector3.Cross(b - a, c - a);
var norm = Vector3.Normalize(dir);
return norm;
}
}
}
Form the cross-product of vectors BA and BC. See http://mathworld.wolfram.com/CrossProduct.html.
You need to calculate the cross product of any two non-parallel vectors on the surface. Since you have three points, you can figure this out by taking the cross product of, say, vectors AB and AC.
When you do this, you're calculating a surface normal, of which Wikipedia has a pretty extensive explanation.

C# code snippet calculating the surface and vertex normals

I need a C# code snippet calculating the surface and vertex normals. Kind of surface is triangulated 3D closed mesh. The required code snippet must be able to use a vertex set and triangleindices. These are ready to use at the moment. The surface of 3D mesh object is not smooth, so it needs to be smoothed.
Could you help me.
It sounds like you're trying to display your 3D mesh and apply a smooth shading appearance by interpolating surface normals, such as in Phong shading, and you need to calculate the normals first. This is different from smoothing the surface of the mesh itself, since that implies altering the positions of its vertices.
Surface normals can be calculated by getting the vector cross product of two edges of a triangle.
As far as code, I'm unaware of any C# examples, but here is one in C++ that should be easy to port. It is taken from the popular NeHe tutorials for OpenGL:
void calcNormal(float v[3][3], float out[3]) // Calculates Normal For A Quad Using 3 Points
{
float v1[3],v2[3]; // Vector 1 (x,y,z) & Vector 2 (x,y,z)
static const int x = 0; // Define X Coord
static const int y = 1; // Define Y Coord
static const int z = 2; // Define Z Coord
// Finds The Vector Between 2 Points By Subtracting
// The x,y,z Coordinates From One Point To Another.
// Calculate The Vector From Point 1 To Point 0
v1[x] = v[0][x] - v[1][x]; // Vector 1.x=Vertex[0].x-Vertex[1].x
v1[y] = v[0][y] - v[1][y]; // Vector 1.y=Vertex[0].y-Vertex[1].y
v1[z] = v[0][z] - v[1][z]; // Vector 1.z=Vertex[0].y-Vertex[1].z
// Calculate The Vector From Point 2 To Point 1
v2[x] = v[1][x] - v[2][x]; // Vector 2.x=Vertex[0].x-Vertex[1].x
v2[y] = v[1][y] - v[2][y]; // Vector 2.y=Vertex[0].y-Vertex[1].y
v2[z] = v[1][z] - v[2][z]; // Vector 2.z=Vertex[0].z-Vertex[1].z
// Compute The Cross Product To Give Us A Surface Normal
out[x] = v1[y]*v2[z] - v1[z]*v2[y]; // Cross Product For Y - Z
out[y] = v1[z]*v2[x] - v1[x]*v2[z]; // Cross Product For X - Z
out[z] = v1[x]*v2[y] - v1[y]*v2[x]; // Cross Product For X - Y
ReduceToUnit(out); // Normalize The Vectors
}
The normalization function ReduceToUnit() can be found there as well.
Note that this calculates a surface normal for a single triangle. Since you give no information about how your vertices and indices are stored, I will leave it up to you to derive the set of triangles you need to pass to this function.
EDIT: As an additional note, I think the "winding direction" of your triangles is significant. Winding in the wrong direction will cause the normal to point in the opposite direction as well.

Categories