If I have three points and always want the visible face should be the side that is "facing" from origo, is there a shortcut to calculate the normal of the plane ?
Like this
mesh.Positions.Add(p0);
mesh.Positions.Add(p1);
mesh.Positions.Add(p2);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
normal = Vector3D(1,1,1);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
model = new GeometryModel3D(mesh, material);
Or do I have to calculate the normal every time ?
If I have to calculate the normal, what is the algorithm for that, I have looked on the internet and tried a couple methods but they make me suspicious, like this one.
normal = CalculateNormal(p0, p1, p2);
Where CalculateNormal is
public static Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
{
Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
Vector3D v1 = new Vector3D(p1.X - p2.X, p1.Y - p2.Y, p2.Z - p1.Z);
return Vector3D.CrossProduct(v0, v1);
}
should it not be
Vector3D v1 = new Vector3D(p1.X - p2.X, p1.Y - p2.Y, p1.Z - p2.Z);
instead ?
/Stefan
The following works well
private Model3DGroup CreateTriangleSide(Point3D p0, Point3D p1, Point3D p2, Material material)
{
MeshGeometry3D mesh = null;
GeometryModel3D model = null;
Model3DGroup group = new Model3DGroup();
Vector3D normal;
//
// Front side of jagged part
//
mesh = new MeshGeometry3D();
mesh.Positions.Add(p0);
mesh.Positions.Add(p1);
mesh.Positions.Add(p2);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
normal = CalculateNormal(p0, p1, p2);
normal = Normalize(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
model = new GeometryModel3D(mesh, material);
group.Children.Add(model);
//
// Front side of the surface below the jagged edge
//
Point3D p3 = new Point3D(p1.X, p1.Y, bh);
Point3D p4 = new Point3D(p2.X, p2.Y, bh);
return group;
}
public const double RADDEGC = (Math.PI / 180.0);
public enum ANGLETYPE { RAD, DEG };
/*
* Takes the angle and the Z value to create a 3D point in space
*
* #param angle The angle
* #param radius The radius of the circle
* #param z The z value
* #param t The angle type, for example RAD (radians) or DEG (degress
*
*/
public static Point3D CP(double radius, double angle, double z = 0, ANGLETYPE angtype = ANGLETYPE.RAD)
{
Point3D p = new Point3D();
p.Z = z;
//
if (angtype == ANGLETYPE.RAD)
{
p.X = radius * Math.Cos(angle);
p.Y = radius * Math.Sin(angle);
}
else
{
p.X = radius * Math.Cos(angle * RADDEGC);
p.Y = radius * Math.Sin(angle * RADDEGC);
}
return p;
}
public static Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
{
Vector3D a1 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
Vector3D b1 = new Vector3D(p2.X - p0.X, p2.Y - p0.Y, p2.Z - p0.Z);
Vector3D dir = Vector3D.CrossProduct(a1, b1);
return dir;
}
public static Vector3D Normalize(Vector3D norm)
{
double fac1 = Math.Sqrt((norm.X * norm.X) + (norm.Y * norm.Y) + (norm.Z * norm.Z));
if (fac1 == 0)
{
return norm;
}
norm = new Vector3D(norm.X / fac1, norm.Y / fac1, norm.Z / fac1);
return norm;
}
Related
I have an image on which I choose a random point. The image is rotated by any degree the user wishes. The goal here is to find the new coordinate of the pixel. I have tried it this way with the function RotatePoint where the original position of the pixel was (100, 370) and the image gets rotated by 270 degrees, but the new coordinate is not correct. How would I be able to get the correct new coordinate?
static public void RotatePoint(float angle)
{
var a = angle * System.Math.PI / 180.0;
float cosa = (float)Math.Cos(a), sina = (float)Math.Sin(a);
float x = 100 * cosa - 370 * sina;
float y = 100 * sina + 370 * cosa;
Console.WriteLine(x);
Console.WriteLine(y);
}
private static Bitmap RotateImage(Bitmap bmp, float angle)
{
Bitmap rotatedImage = new Bitmap(bmp.Width, bmp.Height);
rotatedImage.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
// Set the rotation point to the center in the matrix
g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
// Rotate
g.RotateTransform(angle);
// Restore rotation point in the matrix
g.TranslateTransform(-bmp.Width / 2, -bmp.Height / 2);
// Draw the image on the bitmap
g.DrawImage(bmp, new Point(0, 0));
}
return rotatedImage;
}
You perform 2 translation transformations on your image that you don't take into account into your coordinate calculations:
// Set the rotation point to the center in the matrix
g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
and
// Restore rotation point in the matrix
g.TranslateTransform(-bmp.Width / 2, -bmp.Height / 2);
Here is a fix, with both translations taken into account, where xRotationCenter and yRotationCenter should be your bitmap width and height:
public static void RotatePoint(float x = 100, float y = 377, float xRotationCenter, float yRotationCenter, float angleInDegree)
{
var angleInRadiant = (angleInDegree / 180.0) * Math.PI;
var cosa = (float)Math.Cos(angleInRadiant);
var sina = (float)Math.Sin(angleInRadiant);
// First translation
float t1x = x - xRotationCenter;
float t1y = y - yRotationCenter;
// Rotation
float rx = t1x * cosa - t1y * sina;
float ry = t1x * sina + t1y * cosa;
// seconde translation
float x = rx + xRotationCenter;
float y = ry + yRotationCenter;
Console.WriteLine(x);
Console.WriteLine(y);
}
I'm trying to implement, using SharpDX11, a ray/mesh intersection method using the GPU. I've seen from an older post (Older post) that this can be done using the Compute Shader; but I need help in order to create and define the buffer outside the .hlsl code.
My HLSL code is the following:
struct rayHit
{
float3 intersection;
};
cbuffer cbRaySettings : register(b0)
{
float3 rayFrom;
float3 rayDir;
uint TriangleCount;
};
StructuredBuffer<float3> positionBuffer : register(t0);
StructuredBuffer<uint3> indexBuffer : register(t1);
AppendStructuredBuffer<rayHit> appendRayHitBuffer : register(u0);
void TestTriangle(float3 p1, float3 p2, float3 p3, out bool hit, out float3 intersection)
{
//Perform ray/triangle intersection
//Compute vectors along two edges of the triangle.
float3 edge1, edge2;
float distance;
//Edge 1
edge1.x = p2.x - p1.x;
edge1.y = p2.y - p1.y;
edge1.z = p2.z - p1.z;
//Edge2
edge2.x = p3.x - p1.x;
edge2.y = p3.y - p1.y;
edge2.z = p3.z - p1.z;
//Cross product of ray direction and edge2 - first part of determinant.
float3 directioncrossedge2;
directioncrossedge2.x = (rayDir.y * edge2.z) - (rayDir.z * edge2.y);
directioncrossedge2.y = (rayDir.z * edge2.x) - (rayDir.x * edge2.z);
directioncrossedge2.z = (rayDir.x * edge2.y) - (rayDir.y * edge2.x);
//Compute the determinant.
float determinant;
//Dot product of edge1 and the first part of determinant.
determinant = (edge1.x * directioncrossedge2.x) + (edge1.y * directioncrossedge2.y) + (edge1.z * directioncrossedge2.z);
//If the ray is parallel to the triangle plane, there is no collision.
//This also means that we are not culling, the ray may hit both the
//back and the front of the triangle.
if (determinant == 0)
{
distance = 0.0f;
intersection = float3(0, 0, 0);
hit = false;
}
float inversedeterminant = 1.0f / determinant;
//Calculate the U parameter of the intersection point.
float3 distanceVector;
distanceVector.x = rayFrom.x - p1.x;
distanceVector.y = rayFrom.y - p1.y;
distanceVector.z = rayFrom.z - p1.z;
float triangleU;
triangleU = (distanceVector.x * directioncrossedge2.x) + (distanceVector.y * directioncrossedge2.y) + (distanceVector.z * directioncrossedge2.z);
triangleU = triangleU * inversedeterminant;
//Make sure it is inside the triangle.
if (triangleU < 0.0f || triangleU > 1.0f)
{
distance = 0.0f;
intersection = float3(0, 0, 0);
hit = false;
}
//Calculate the V parameter of the intersection point.
float3 distancecrossedge1;
distancecrossedge1.x = (distanceVector.y * edge1.z) - (distanceVector.z * edge1.y);
distancecrossedge1.y = (distanceVector.z * edge1.x) - (distanceVector.x * edge1.z);
distancecrossedge1.z = (distanceVector.x * edge1.y) - (distanceVector.y * edge1.x);
float triangleV;
triangleV = ((rayDir.x * distancecrossedge1.x) + (rayDir.y * distancecrossedge1.y)) + (rayDir.z * distancecrossedge1.z);
triangleV = triangleV * inversedeterminant;
//Make sure it is inside the triangle.
if (triangleV < 0.0f || triangleU + triangleV > 1.0f)
{
distance = 0.0f;
intersection = float3(0, 0, 0);
hit = false;
}
//Compute the distance along the ray to the triangle.
float raydistance;
raydistance = (edge2.x * distancecrossedge1.x) + (edge2.y * distancecrossedge1.y) + (edge2.z * distancecrossedge1.z);
raydistance = raydistance * inversedeterminant;
//Is the triangle behind the ray origin?
if (raydistance < 0.0f)
{
distance = 0.0f;
intersection = float3(0, 0, 0);
hit = false;
}
intersection = rayFrom + (rayDir * distance);
hit = true;
}
[numthreads(64, 1, 1)]
void CS_RayAppend(uint3 tid : SV_DispatchThreadID)
{
if (tid.x >= TriangleCount)
return;
uint3 indices = indexBuffer[tid.x];
float3 p1 = positionBuffer[indices.x];
float3 p2 = positionBuffer[indices.y];
float3 p3 = positionBuffer[indices.z];
bool hit;
float3 p;
TestTriangle(p1, p2, p3, hit, p);
if (hit)
{
rayHit hitData;
hitData.intersection = p;
appendRayHitBuffer.Append(hitData);
}
}
While the following is part of my c# implementation but I'm not able to understand how lo load buffers for compute shader.
int count = obj.Mesh.Triangles.Count;
int size = 8; //int+float for every hit
BufferDescription bufferDesc = new BufferDescription() {
BindFlags = BindFlags.UnorderedAccess | BindFlags.ShaderResource,
Usage = ResourceUsage.Default,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.BufferStructured,
StructureByteStride = size,
SizeInBytes = size * count
};
Buffer buffer = new Buffer(device, bufferDesc);
UnorderedAccessViewDescription uavDescription = new UnorderedAccessViewDescription() {
Buffer = new UnorderedAccessViewDescription.BufferResource() { FirstElement = 0, Flags = UnorderedAccessViewBufferFlags.None, ElementCount = count },
Format = SharpDX.DXGI.Format.Unknown,
Dimension = UnorderedAccessViewDimension.Buffer
};
UnorderedAccessView uav = new UnorderedAccessView(device, buffer, uavDescription);
context.ComputeShader.SetUnorderedAccessView(0, uav);
var code = HLSLCompiler.CompileFromFile(#"Shaders\TestTriangle.hlsl", "CS_RayAppend", "cs_5_0");
ComputeShader _shader = new ComputeShader(device, code);
Buffer positionsBuffer = new Buffer(device, Utilities.SizeOf<Vector3>(), ResourceUsage.Default, BindFlags.None, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
context.UpdateSubresource(ref data, positionsBuffer);
context.ComputeShader.Set(_shader);
Inside my c# implementation i'm considering only one ray (with its origin and direction) and I would like to use the shader to check the intersection with all the triangles of the mesh. I'm already able to do that using the CPU but for 20k+ triangles the computation took too long even if i'm already using parallel coding.
I need to do a boolean subtraction between two models in C#. One of the meshs will be entirely within the other mesh, so I was hoping to reverse the normals for the one model and add the two models together. I am at a loss on how to invert the normals though.
This is how I'm calculating a surface normal:
//creates surface normals
Vector3D CalculateSurfaceNormal(Point3D p1, Point3D p2, Point3D p3)
{
Vector3D v1 = new Vector3D(0, 0, 0); // Vector 1 (x,y,z) & Vector 2 (x,y,z)
Vector3D v2 = new Vector3D(0, 0, 0);
Vector3D normal = new Vector3D(0, 0, 0);
// Finds The Vector Between 2 Points By Subtracting
// The x,y,z Coordinates From One Point To Another.
// Calculate The Vector From Point 2 To Point 1
v1.X = p1.X - p2.X;
v1.Y = p1.Y - p2.Y;
v1.Z = p1.Z - p2.Z;
// Calculate The Vector From Point 3 To Point 2
v2.X = p2.X - p3.X;
v2.Y = p2.Y - p3.Y;
v2.Z = p2.Z - p3.Z;
// Compute The Cross Product To Give Us A Surface Normal
normal.X = v1.Y * v2.Z - v1.Z * v2.Y; // Cross Product For Y - Z
normal.Y = v1.Z * v2.X - v1.X * v2.Z; // Cross Product For X - Z
normal.Z = v1.X * v2.Y - v1.Y * v2.X; // Cross Product For X - Y
normal.Normalize();
return normal;
}
I was advised to reverse the normal by negating it:
n = CalculateSurfaceNormal(p1, p2, p3);
n = new Vector3D(-1 * n.X, -1 * n.Y, -1 * n.Z);
I find the values are negated, but when I view the model in a 3D program, there is no change in the model.
Another suggestion was to try backface culling by changing the order of the vectors. I tried this by swapping the order of v1 and v2:
//creates invertedsurface normals
Vector3D CalculateInvertedSurfaceNormal(Point3D p1, Point3D p2, Point3D p3)
{
Vector3D v1 = new Vector3D(0, 0, 0); // Vector 1 (x,y,z) & Vector 2 (x,y,z)
Vector3D v2 = new Vector3D(0, 0, 0);
Vector3D normal = new Vector3D(0, 0, 0);
// Finds The Vector Between 2 Points By Subtracting
// The x,y,z Coordinates From One Point To Another.
// Calculate The Vector From Point 2 To Point 1
v2.X = p1.X - p2.X;
v2.Y = p1.Y - p2.Y;
v2.Z = p1.Z - p2.Z;
// Calculate The Vector From Point 3 To Point 2
v1.X = p2.X - p3.X;
v1.Y = p2.Y - p3.Y;
v1.Z = p2.Z - p3.Z;
// Compute The Cross Product To Give Us A Surface Normal
normal.X = v1.Y * v2.Z - v1.Z * v2.Y; // Cross Product For Y - Z
normal.Y = v1.Z * v2.X - v1.X * v2.Z; // Cross Product For X - Z
normal.Z = v1.X * v2.Y - v1.Y * v2.X; // Cross Product For X - Y
normal.Normalize();
return normal;
}
No change in the model.
Here is the whole code:
private void SaveMoldMeshtoStlFile(MeshGeometry3D mesh, string filename)
{
if (mesh == null)
return;
if (File.Exists(filename))
{
File.SetAttributes(filename, FileAttributes.Normal);
File.Delete(filename);
}
Point3DCollection vertexes = mesh.Positions;
Int32Collection indexes = mesh.TriangleIndices;
Point3D p1, p2, p3;
Vector3D n;
string text;
using (TextWriter writer = new StreamWriter(filename))
{
writer.WriteLine("solid Bolus");
for (int v = 0; v < mesh.TriangleIndices.Count(); v += 3)
{
//gather the 3 points for the face and the normal
p1 = vertexes[indexes[v]];
p2 = vertexes[indexes[v + 1]];
p3 = vertexes[indexes[v + 2]];
n = CalculateInvertedSurfaceNormal(p1, p2, p3);
text = string.Format("facet normal {0} {1} {2}", n.X,n.Y, n.Z);
writer.WriteLine(text);
writer.WriteLine("outer loop");
text = String.Format("vertex {0} {1} {2}", p1.X, p1.Y, p1.Z);
writer.WriteLine(text);
text = String.Format("vertex {0} {1} {2}", p2.X, p2.Y, p2.Z);
writer.WriteLine(text);
text = String.Format("vertex {0} {1} {2}", p3.X, p3.Y, p3.Z);
writer.WriteLine(text);
writer.WriteLine("endloop");
writer.WriteLine("endfacet");
}
}
}
//creates inverted surface normals
Vector3D CalculateInvertedSurfaceNormal(Point3D p1, Point3D p2, Point3D p3)
{
Vector3D v1 = new Vector3D(0, 0, 0); // Vector 1 (x,y,z) & Vector 2 (x,y,z)
Vector3D v2 = new Vector3D(0, 0, 0);
Vector3D normal = new Vector3D(0, 0, 0);
// Finds The Vector Between 2 Points By Subtracting
// The x,y,z Coordinates From One Point To Another.
// Calculate The Vector From Point 2 To Point 1
v2.X = p1.X - p2.X;
v2.Y = p1.Y - p2.Y;
v2.Z = p1.Z - p2.Z;
// Calculate The Vector From Point 3 To Point 2
v1.X = p2.X - p3.X;
v1.Y = p2.Y - p3.Y;
v1.Z = p2.Z - p3.Z;
// Compute The Cross Product To Give Us A Surface Normal
normal.X = v1.Y * v2.Z - v1.Z * v2.Y; // Cross Product For Y - Z
normal.Y = v1.Z * v2.X - v1.X * v2.Z; // Cross Product For X - Z
normal.Z = v1.X * v2.Y - v1.Y * v2.X; // Cross Product For X - Y
normal.Normalize();
return normal;
}
Is there an error with my code? Am I missing something? I've tried out the exported models in a few different programs, and all are showing the exported model still has the normals facing outwards. I tried flipping the normals in Blender and found the other programs also showed the normals flipped, so I'm fairly sure it's a problem with my program.
Figured out the solution.
The order of points for each triangle is crucial. If the order of points doesn't support the normal's direction, I'm finding other programs will automatically correct the normal.
Where I had this:
//gather the 3 points for the face and the normal
p1 = vertexes[indexes[v]];
p2 = vertexes[indexes[v + 1]];
p3 = vertexes[indexes[v + 2]];
n = CalculateInvertedSurfaceNormal(p1, p2, p3);
I instead reversed the direction of the points by changed to this:
//gather the 3 points for the face and the normal
p3 = vertexes[indexes[v]];
p2 = vertexes[indexes[v + 1]];
p1 = vertexes[indexes[v + 2]];
n = CalculateInvertedSurfaceNormal(p1, p2, p3);
That solved my problem.
I have created a Venn diagram using simple Graphics functions provided by WinForm in the onPaint event. Here is my code for creating the Venn.
using (Brush brushLeft = new SolidBrush(LeftVennColor))
{
leftvennPath.AddEllipse(leftVenn);
leftOnlyRegion = new Region(leftVenn);
e.Graphics.FillEllipse(brushLeft, leftVenn);
e.Graphics.DrawEllipse(pen, leftVenn);
}
using (Brush brushRight = new SolidBrush(RightVennColor))
{
rightvennPath.AddEllipse(rightVenn);
rightOnlyRegion = new Region(rightVenn);
e.Graphics.FillEllipse(brushRight, rightVenn);
e.Graphics.DrawEllipse(pen, rightVenn);
}
using (GraphicsPath circle_path = new GraphicsPath())
{
circle_path.AddEllipse(leftVenn);
commonRegion.Intersect(circle_path);
}
using (GraphicsPath circle_path = new GraphicsPath())
{
circle_path.AddEllipse(rightVenn);
commonRegion.Intersect(circle_path);
}
The Venn diagram is created, but with this code my common region is the intersection of both left and right ellipses. I want to have two separate regions out of that common area, which is separated by a line. Here is the image for that,
So basically, I need all these four regions separated and clickable ( different colors for each region ).. I use Region.IsVisible(e.location) in the mouse click event to handle the click event. Could someone please help?
Final solution:
cx0, cy0, radius0 center and radius of left circle
cx1, cy1, radius1 center and radius of right circle
The function takes the regions by ref.
private void FindRegions(int cx0, int cx1, int cy0, int cy1, int radius0, int radius1, ref Region rgnLeft, ref Region rgnRight)
{
//Left circle
GraphicsPath gpL = new GraphicsPath();
//Right circle
GraphicsPath gpR = new GraphicsPath();
//The right small region (yellow color)
GraphicsPath gp = new GraphicsPath();
//Points of intersection
PointF pnt1 = new PointF();
PointF pnt2 = new PointF();
Graphics g = this.CreateGraphics();
gpL.AddEllipse(new Rectangle(cx0 - radius0, cy0 - radius0, 2 * radius0, 2 * radius0));
gpR.AddEllipse(new Rectangle(cx1 - radius0, cy1 - radius1, 2 * radius1, 2 * radius1));
g.DrawPath(Pens.Red, gpL);
g.DrawPath(Pens.Blue, gpR);
int numPoints = FindCircleCircleIntersections((single)cx0, (single)cx1, (single)cy0, (single)cy1, (single)radius0, (single)radius1, ref pnt1, ref pnt2);
if (numPoints != 2)
{
//No regions
return;
}
Double theta, fe;
Double dx = (double)pnt1.X - (double)pnt2.X;
Double dy = (double)pnt1.Y - (double)pnt2.Y;
Double dist = Math.Sqrt(dx * dx + dy * dy);
PointF minPoint, maxPoint;
if (pnt2.Y < pnt1.Y)
{
minPoint = pnt2;
maxPoint = pnt1;
}
else
{
minPoint = pnt1;
maxPoint = pnt2;
}
//theta is the angle between the three points pnt1, pnt2 and left center
theta = Math.Acos((dist / 2D) / 100D);
theta = (theta * 180D) / Math.PI;
theta = 90D - theta;
theta *= 2D;
//fe is the starting angle of the point(between pnt1 and pnt2) with
//the smaller y coordinate. The angle is measured from x axis and clockwise
fe = Math.Asin( Math .Abs ( (-(Double)minPoint.Y + (double)cy0) )/ (double)radius0);
fe = (fe * 180D) / Math.PI;
if (minPoint.X > cx0 && minPoint.Y >= cy0)
{
//fe = (90 - fe) + 270;
}
else if (minPoint.X > cx0 && minPoint.Y < cy0)
{
fe = (90D - fe) + 270D;
}
else if (minPoint.X == cx0 && minPoint.Y < cy0)
{
fe = 270D;
}
else
{
fe += 180D;
}
gp.AddArc(new Rectangle(cx0 - radius0, cy0 - radius0, 2 * radius0, 2 * radius0), (float)fe, (float)theta);
gp.AddLine(maxPoint, minPoint);
gp.CloseFigure();
g.DrawPath(Pens.Green, gp);
Region rgnL = new Region(gpL);
Region rgnR = new Region(gpR);
Region rgnInt = new Region(gpL);
Region rgn = new Region(gp); //right small
rgnInt.Intersect(rgnR);
rgnInt.Exclude(rgn); //left small
g.FillRegion(Brushes.DarkGreen, rgnInt);
g.FillRegion(Brushes.DarkGray, rgn);
rgnLeft = rgnInt.Clone();
rgnRight = rgn.Clone();
g.Dispose();
rgnL.Dispose();
rgnR.Dispose();
rgnInt.Dispose();
rgn.Dispose();
gpL.Dispose();
gpR.Dispose();
gp.Dispose();
}
private int FindCircleCircleIntersections(Single cx0, Single cx1, Single cy0, Single cy1, Single radius0, Single radius1,
ref PointF intersection1, ref PointF intersection2)
{
// Find the distance between the centers.
Single dx = cx0 - cx1;
Single dy = cy0 - cy1;
Double dist = Math.Sqrt(dx * dx + dy * dy);
// See how many solutions there are.
if (dist > radius0 + radius1)
{
//No solutions, the circles are too far apart.
intersection1 = new PointF(Single.NaN, Single.NaN);
intersection2 = new PointF(Single.NaN, Single.NaN);
return 0;
}
else if (dist < Math.Abs(radius0 - radius1))
{
// No solutions, one circle contains the other.
intersection1 = new PointF(Single.NaN, Single.NaN);
intersection2 = new PointF(Single.NaN, Single.NaN);
return 0;
}
else if ((dist == 0) && (radius0 == radius1))
{
// No solutions, the circles coincide.
intersection1 = new PointF(Single.NaN, Single.NaN);
intersection2 = new PointF(Single.NaN, Single.NaN);
return 0;
}
else
{
// Find a and h.
Double a = (radius0 * radius0 - radius1 * radius1 + dist * dist) / (2 * dist);
Double h = Math.Sqrt(radius0 * radius0 - a * a);
// Find P2.
Double cx2 = cx0 + a * (cx1 - cx0) / dist;
Double cy2 = cy0 + a * (cy1 - cy0) / dist;
// Get the points P3.
intersection1 = new PointF( (Single)(cx2 + h * (cy1 - cy0) / dist), (Single)(cy2 - h * (cx1 - cx0) / dist));
intersection2 = new PointF( (Single)(cx2 - h * (cy1 - cy0) / dist), (Single)(cy2 + h * (cx1 - cx0) / dist));
// See if we have 1 or 2 solutions.
if (dist == radius0 + radius1) return 1;
return 2;
}
}
EDIT
Region has only a Fill method and no Draw one. So you cant do it with regions. GraphicPath
however HAS both Fill and Draw.
You said that you need to validate if a point is inside the region BUT you can do the same with GraphicPath
myGraphicPath.IsVisible();
So, dont use regions but paths. It is better for another reason. GraphicPath can draw AntiAlias but regions dont. Set
g.SmoothingMode = SmoothingMode.AntiAlias;
To enable AntiAlias. All goodies with paths!
Change the function name from FindRegions to FindPaths and send paths as refference:
private void FindPaths(int cx0, int cx1, int cy0, int cy1, int radius0, int radius1, ref GraphicsPath gpLeft, ref GraphicsPath gpRight)
The code is exactly the same, but add in the and:
private void FindPaths(int cx0, int cx1, int cy0, int cy1, int radius0, int radius1, ref GraphicsPath gpLeft, ref GraphicsPath gpRight)
{
...
...
//Above code exactly the same
//replace these
//rgnLeft = rgnInt.Clone();
//rgnRight = rgn.Clone();
//with these
GraphicsPath gpLeftSmall = (GraphicsPath)gp.Clone();
Matrix matrix = new Matrix();
PointF pntf = new PointF();
pntf.X = (float)(Math.Min((double)pnt1.X, (double)pnt2.X) + Math.Abs((double)(pnt1.X - pnt2.X) / 2D));
pntf.Y = (float)(Math.Min((double)pnt1.Y, (double)pnt2.Y) + Math.Abs((double)(pnt1.Y - pnt2.Y) / 2D));
matrix.RotateAt(180, pntf);
gpLeftSmall.Transform(matrix);
g.DrawPath(Pens.Black, gpLeftSmall); //If you want to draw it
//passed by refference
gpLeft = gpLeftSmall.Clone();
gpRight = gp.Clone();
g.Dispose();
rgnL.Dispose();
rgnR.Dispose();
rgnInt.Dispose();
rgn.Dispose();
gpL.Dispose();
gpR.Dispose();
gp.Dispose();
gpLeftSmall.Dispose();
matrix.Dispose();
}
Reference:
Determine where two circles intersect
I am trying to implement wall following steering behaviour in C#. For that I have a point and a line segment. All I need is a perpendicular point C so that line segment CD is perpendicular to AB. http://puu.sh/1xrxQ This is the scenario. The point is moving so I need to calculate it every time. I am new to c# so I don't know how it works.
This is what I have tried till now to get it working.
private double DotProduct(Point pointA, Point pointB, Point pointC)
{
Point AB = new Point();
Point BC = new Point();
AB.X = pointB.X - pointA.X;
AB.Y = pointB.Y - pointA.Y;
BC.X = pointC.X - pointB.X;
BC.Y = pointC.Y - pointB.Y;
double dot = AB.X * BC.X + AB.Y * BC.Y;
return dot;
}
//Compute the cross product AB x AC
private double CrossProduct(Point pointA, Point pointB, Point pointC)
{
Point AB = new Point();
Point AC = new Point();
AB.X = pointB.X - pointA.X;
AB.Y = pointB.Y - pointA.Y;
AC.X = pointC.X - pointA.X;
AC.Y = pointC.Y - pointA.Y;
double cross = AB.X * AC.Y - AB.Y * AC.X;
return cross;
}
//Compute the distance from A to B
double Distance(Point pointA, Point pointB)
{
double d1 = pointA.X - pointB.X;
double d2 = pointA.Y - pointB.Y;
return Math.Sqrt(d1 * d1 + d2 * d2);
}
//Compute the distance from AB to C
//if isSegment is true, AB is a segment, not a line.
double LineToPointDistance2D(Point pointA, Point pointB, Point pointC, bool isSegment)
{
double dist = CrossProduct(pointA, pointB, pointC) / Distance(pointA, pointB);
if (isSegment)
{
double dot1 = DotProduct(pointA, pointB, pointC);
if (dot1 > 0)
return Distance(pointB, pointC);
double dot2 = DotProduct(pointB, pointA, pointC);
if (dot2 > 0)
return Distance(pointA, pointC);
}
return Math.Abs(dist);
}
Not tested, but mathematically this should work
Point intersectionPoint(Point A, Point B, Point C) {
//check for slope of 0 or undefined
if (A.Y == B.Y) return new Point (C.X, A.Y);
if (A.X == B.X) return new Point (A.X, C.Y);
//slope = (y1 - y2) / (x1 - x2)
double slopeAB = (A.Y - B.Y) / (A.X - B.X);
//perpendicular slope is the negative reciprocal
double slopeCD = -1 / slopeAB;
//solve for b in y = mx + b of each line
// b = y - mx
double bAB = A.Y - slopeAB * A.X;
double bCD = C.Y - slopeCD * C.X;
double dX, dY;
//intersection of two lines is m1x + b1 = m2x + b2
//solve for x: x = (b2 - b1) / (m1 - m2)
//find y by plugging x into one of the equations
dX = (bCD - bAB) / (slopeAB - slopeCD);
dY = slopeAB * dX + bAB;
return new Point(dX, dY);
}