Check Intersection Between Line and Rotated Rectangle - c#

I have try many things without finding the good solution so here I am.
In my game (2D) I have to check collision with all my Object (house, garage..) which are image inside Rotated Rectangle, between a ray from a Point A to Point B.
I'm using Xna and there some code:
public void Update(List<Obstacle> Lob, DragObj Ldo)
{
bool inter = false;
Point A;
Point B;
A = new Point((int)pos.X, (int)pos.Y);
B = new Point((int)Ldo.Position.X, (int)Ldo.Position.Y);
for (int j = 0; j < Lob.Count(); j++)
{
if (inter = interclass.LineIntersectsRect(A, B, Lob[j].Shape)) // I have this for the moment, Shape is the rectangle but not rotated )
{
inter = true;
islight = false;
}
else
{
inter = false;
}
}
}
So to solve my problem, whether I find a solution to have a rotatedRectangle Object with a method to check collision with line. Whether totally something else, maybe only check collision between yy straight and each rotated Rectangle Axis?
Thanks for your advices.

I have solver this problem by checking intersection between my line and each side of the rotated Rectangle (I have to rotate each Line-side of the rectangle first).
I will post the little algo soon.

I don't know C# but...
There is this algorithm that can get the closest point on a line from a point.
(Note that the closestPointOnLine function is not my code)
var closestPointOnLine = function(line1, point1)
{
var A1 = line1.y2 - line1.y1;
var B1 = line1.x1 - line1.x2;
var C1 = A1 * line1.x1 + B1 * line1.y1;
var C2 = -B1 * point1.x + A1 * point1.y;
var det = A1 * A1 + B1 * B1;
var cx = 0;
var cy = 0;
if(det !== 0)
{
cx = ((A1 * C1 - B1 * C2) / det);
cy = ((A1 * C2 + B1 * C1) / det);
}else{
cx = point1.x;
cy = point1.y;
}
return {
x : constrain(cx, Math.min(line1.x1, line1.x2), Math.max(line1.x1, line1.x2)),
y : constrain(cy, Math.min(line1.y1, line1.y2), Math.max(line1.y1, line1.y2)),
};
};
Before we go any further let's make it clear that:
Our line is:
var lineToTest = {
x1: someNumber
y1: someNumber,
x2: someNumber,
y2: someNumber
};
And that our rotated rectangle contains:
var rectToTest = {
points: [
{
x : someNumber,
y : someNumber,
},
{
x : someNumber,
y : someNumber,
},
{
x : someNumber,
y : someNumber,
},
{
x : someNumber,
y : someNumber,
},
],
};
We then take the lineToTest and take it's first point and begin using the closestPointOnLine to get a point on a line of the rectToTest,
We then check if that point is touching the lineToTest, if it is not repeat for the other lines in the rectangle.
Now I don't actually know the code to check if a point is touching a line:
But it might go something like this:
function isLineTouchingPoint(line1, point)
{
//Other code here
//You'll have to use trigonometry for this one though
return boolean;
}
Now you could convert this code into C# to get it to work.

Related

How to determine if a Point is inside of a 2D Polygon that has Arcs

I have been using the following references to try to determine if a Point is inside of a 2D Polygon that has Arcs:
Is a point inside of 2D polygon, no curves
Is a point inside a compound polygon (C#)
Is a point inside a curve (Theory)
My approach uses Ray Casting to determine if a point is within the polygon boundary. This is my code that attempts to string the references together (C#):
public static bool IsInsideBoundary(Polyline pline, Point3d pnt, Document currentDoc)
{
try
{
if (pline.Closed == true)
{
Tools.Log("Polyline is Closed");
// Check if point is on the line -> WORKS
if (IsPointOnCurve(pline, pnt))
{
Log("Point is on the Boundary line");
return true;
}
else
{
int numOfVerts = pline.NumberOfVertices;
// Get bounding box of boundary
double minX = pline.GetPoint3dAt(0).X;
double maxX = pline.GetPoint3dAt(0).X;
double minY = pline.GetPoint3dAt(0).Y;
double maxY = pline.GetPoint3dAt(0).Y;
for (int i = 1; i < numOfVerts; i++)
{
Point3d q = pline.GetPoint3dAt(i);
minX = Math.Min(q.X, minX);
maxX = Math.Max(q.X, maxX);
minY = Math.Min(q.Y, minY);
maxY = Math.Max(q.Y, minY);
}
// Check if the given point outside of the bounding box
if (pnt.X < minX || pnt.X > maxX || pnt.Y < minY || pnt.Y > maxY)
{
return false;
}
Log("Bounding Box check passed...");
bool inside = false;
for (int i = 0, j = numOfVerts - 1; i < numOfVerts; j = i++)
{
double a1 = pline.GetPoint3dAt(i).X, a2 = pline.GetPoint3dAt(i).Y;
double b1 = pnt.X, b2 = pnt.Y;
double c1 = pline.GetPoint3dAt(j).X, c2 = pline.GetPoint3dAt(j).Y;
// Use the Jordan Curve Theorem
double d1 = (c1 - a1) * (b2 - a2) / (c2 - a2) + a1;
// Split arc into monotone parts and check bounds
if ((a2 > b2) != (c2 > b2) && b1 < d1)
{
inside = !inside;
}
}
Log("Point is within the boundary");
return inside;
}
}
else
{
Log("Boundary is not closed.");
}
}
catch (System.Exception e)
{
Log("InsideBoundary() Failed. Exception: " + e.Message, true);
}
return false;
}
Note that some of the calls I am making (i.e. .GetPoint3dAt()) are from the AutoCAD .NET API. This approach works fine for any polygon that has no arcs, but when an arc is introduced, and the point lies within the bounds of the polygon perimeter, a false negative is produced.
Here is an example of the polygons I am testing:
Any help would be greatly appreciated, thank you.
I asked this question in the AutoDesk .NET Forum and recieved this solution:
The Answer

Why Radial tree layout drawing algorithm is making crossed edges?

I am implementing radial layout drawing algorithm, according to the publication of mr.Andy Pavlo link [page 18]
The problem is, that my result contains crossed edges. Which is something that is unacceptable. I found some solution, similiar problem link but I was not able to implement them into this algorithm (I would have to change the whole approach to the solution). In addition, the algorithm by Mr. Andy Pavlo should be able to solve this problem. When we look at the result of its algorithm, there are no crossed edges here. What am I doing wrong? Am I missing something? Thank you in advance.
Mr.Pavlo pseudo code of algorithm
My implementation of algorithm
public void RadialPositions(Tree<string> rootedTree, Node<string> vertex, double alfa, double beta,
List<RadialPoint<string>> outputGraph)
{
//check if vertex is root of rootedTree
if (vertex.IsRoot)
{
vertex.Point.X = 0;
vertex.Point.Y = 0;
outputGraph.Add(new RadialPoint<string>
{
Node = vertex,
Point = new Point
{
X = 0,
Y = 0
},
ParentPoint = null
});
}
//Depth of vertex starting from 0
int depthOfVertex = vertex.Depth;
double theta = alfa;
double radius = Constants.CircleRadius + (Constants.Delta * depthOfVertex);
//Leaves number in the subtree rooted at v
int leavesNumber = BFS.BreatFirstSearch(vertex);
foreach (var child in vertex.Children)
{
//Leaves number in the subtree rooted at child
int lambda = BFS.BreatFirstSearch(child);
double mi = theta + ((double)lambda / leavesNumber * (beta - alfa));
double x = radius * Math.Cos((theta + mi) / 2.0);
double y = radius * Math.Sin((theta + mi) / 2.0);
//setting x and y
child.Point.X = x;
child.Point.Y = y;
outputGraph.Add(new RadialPoint<string>
{
Node = child,
Point = new Point
{
X = x,
Y = y,
Radius = radius
},
ParentPoint = vertex.Point
});
if (child.Children.Count > 0)
{
child.Point.Y = y;
child.Point.X = x;
RadialPositions(rootedTree, child, theta, mi, outputGraph);
}
theta = mi;
}
}
BFS algorithm for getting leaves
public static int BreatFirstSearch<T>(Node<T> root)
{
var visited = new List<Node<T>>();
var queue = new Queue<Node<T>>();
int leaves = 0;
visited.Add(root);
queue.Enqueue(root);
while (queue.Count != 0)
{
var current = queue.Dequeue();
if (current.Children.Count == 0)
leaves++;
foreach (var node in current.Children)
{
if (!visited.Contains(node))
{
visited.Add(node);
queue.Enqueue(node);
}
}
}
return leaves;
}
Initial call
var outputPoints = new List<RadialPoint<string>>();
alg.RadialPositions(tree, tree.Root,0, 360, outputPoints);
mr.Pavlo result
My result on simple sample
Math.Cos and Sin expect the input angle to be in radians, not degrees. In your initial method call, your upper angle limit (beta) should be 2 * Math.PI, not 360. This will ensure that all the angles you calculate will be in radians and not degrees.

sloped walled direction and the host for windows and doors revit api

1- How can I find the angle for sloped wall in the x,y.I used the code below to find it for the walls but it didn't work for sloped wall.
When I use it for the ordinary walls it gives XYz like 0,1,0/0,-1,0/1,0,0/-1,0,0
but for the sloped wall it become 0,0,1 all the time. Please, read the code.
2- I want to find the wall Id for the windows and doors in my Revit project using
the API. I can find the openings in the wall but what I actually need is quite the opposite, I need the host.
protected XYZ GetExteriorWallDirection(Element wall)
{
LocationCurve locationCurve
= wall.Location as LocationCurve;
XYZ exteriorDirection = XYZ.BasisZ;
if (locationCurve != null)
{
Curve curve = locationCurve.Curve;
//Write("Wall line endpoints: ", curve);
XYZ direction = XYZ.BasisX;
if (curve is Line)
{
// Obtains the tangent vector of the wall.
direction = curve.ComputeDerivatives(
0, true).BasisX.Normalize();
}
else
{
// An assumption, for non-linear walls,
// that the "tangent vector" is the direction
// from the start of the wall to the end.
direction = (curve.GetEndPoint(1)
- curve.GetEndPoint(0)).Normalize();
}
// Calculate the normal vector via cross product.
exteriorDirection = getCrossProduct(XYZ.BasisZ,direction);
// Flipped walls need to reverse the calculated direction
Wall wa = wall as Wall;
if (wa.Flipped)
{
exteriorDirection = -exteriorDirection;
}
}
return exteriorDirection;
}
protected XYZ getCrossProduct(XYZ a, XYZ b)
{
double ax = a.X;
double ay = a.Y;
double az = a.Z;
double bx = b.X;
double by = b.Y;
double bz = b.Z;
double cx = ay * bz - az * by;//= 3×7 − 4×6 = −3
double cy = az * bx - ax * bz;//= 4×5 − 2×7 = 6
double cz = ax * by - ay * bx;// = 2×6 − 3×5 = −3
XYZ c = new XYZ(cx, cy, cz);
return c;
}
You'll need to get all elements where the HOST_ID_PARAM equals the Wall ID you have. Here is an example. Below is a minimum version of it.
private static void HostedFamilyInstanceOpenings(Wall wall)
{
// Filter all Family Instances where the HOST_ID_PARAM
// equals the wall ID
//
// More information at
// http://thebuildingcoder.typepad.com/
// blog/2010/06/parameter-filter.html#4
BuiltInParameter testParam =
BuiltInParameter.HOST_ID_PARAM;
ParameterValueProvider pvp =
new ParameterValueProvider(
new ElementId((int)testParam));
FilterNumericRuleEvaluator fnrv = new FilterNumericEquals();
ElementId ruleValId = wall.Id;
FilterRule paramFr = new FilterElementIdRule
(pvp, fnrv, ruleValId);
ElementParameterFilter epf =
new ElementParameterFilter(paramFr);
FilteredElementCollector collector =
new FilteredElementCollector(wall.Document);
collector.OfClass(typeof(FamilyInstance)).WherePasses(epf);
IList<Element> hostedFamilyInstances = collector.ToElements();
// Now iterate through the collected family instances
foreach (FamilyInstance instance in hostedFamilyInstances)
{
}
}

How to adjust the distance of one 3D point from another 3D point by a given distance

I am working with point3D and vector3D classes and I need some help adjusting a point by a given distance.
Point A - point residing at coordinate 0,0,0.
Point B - point residing at coordinate 1,1,1.
Vector AB - vector AB which tells me the length between the two points A and B is distance = 1.73205078.
Code:
Point3D A = new Point3D { X = 0, Y = 0, Z = 0 };
Point3D B = new Point3D { X = 1, Y = 1, Z = 1 };
Vector3D AtoB = A - B;
Double distanceBetweenAandB = AtoB.Length; // the distance will be 1.73205078 here.
I would like to adjust point B. I would like to reduce the distance between point A and point B to 0.5 instead of 1 (adjusting to position C as shown in the diagram). I am trying to work out how to do this.
Point A (0,0,0) is known, point B (1,1,1) is known and the distance to adjust by is known (0.5). How do I calculate?
Pseudo code:
Point3D A = new Point3D { X = 0, Y = 0, Z = 0 };
Point3D B = new Point3D { X = 1, Y = 1, Z = 1 };
Double distanceToAdjust = 0.5;
Point3D newCoordinate = B - distanceToAdjust; // this doesnt work!
Adjusted point B shown in diagram below:
I am using my own defined Point3D class and Vector3D class.
Let's assume your given parameters for your points, and create a 3rd, which we'll call newCoordinate, and that point A will be your reference:
Point3D A = new Point3D { X = 0, Y = 0, Z = 0 };
Point3D B = new Point3D { X = 1, Y = 1, Z = 1 };
Double distanceToAdjust = 0.5;
Point3D newCoordinate = new Point3D {
A.X + ((B.X - A.X) * distanceToAdjust),
A.Y + ((B.Y - A.Y) * distanceToAdjust),
A.Z + ((B.Z - A.Z) * distanceToAdjust)
}
Here we see the original points:
Assuming this values, newCoordinate would sit at X=0.5, Y=0.5, Z=0.5. Nice graph follows:
There it is, sitting right in between the two original points.
As a simulation, if you change A and B and assume this values instead:
Point3D A = new Point3D { X = -8, Y = 4, Z = 3 };
Point3D B = new Point3D { X = 3, Y = 2, Z = 1 };
Then newCoordinate position would be X=-2.5, Y=3, Z=2.
Now, same points, but using distanceToAdjust = 1.2:
Keep this two things in mind:
Changes in distance always need a reference point. In my sample, I assumed A; that's why it appears as the first portion of each newCoordinate parameter initialization.
distanceToAdjust was taken as a multiplier factor.
Addendum: The nifty tool I used to help visualization can be found here.
Assuming you implemented vector operations:
if point A is always [0,0,0]
Point3D new = B.Normalize() * distance;
for any two points
Point3D newCoord = A + ((B - A).Normalize() * distance); //move to origin, normalize, scale and move back
not fast solution though.
"the length between the two points A and B is distance = 1"
No, the distance is the square root of three, about 1.732.
The distance from (0,0,0) to (0,0,1) is 1. The distance from (0,0,0) to (0,1,1) is the square root of two. (Think a triangle in two dimensions, and Pythagoas theorem.) The distance from (0,0,0) to (1,1,1) is the square root of three. (Think a triangle in two dimensions, where that dimension is on a plane along the hypothenuse of the previous triangle. AB = √(1² + (√2)²).)
I assume that you don't want to subtract 0.5 from anything, but actually multiply the distance by 0.5, i.e. getting halfways from A to B. You can calculate the point C by taking that part of the distance between point A and point B in each dimension:
Point3D C = new Point3D {
A.X + (B.X - A.X) * distanceToAdjust,
A.Y + (B.Y - A.Y) * distanceToAdjust,
A.Z + (B.Z - A.Z) * distanceToAdjust
};
In pseudo code, here's how I ended up implementing
pointA = …
pointB = …
vectorAB = B-A
desiredDistance = 0.5; // where 0.5 is vectorAB.Length/desiredDistance
vectorAC = vectorAB * desiredDistance ;
pointC = A+vectorAC;
Actual code:
Vector3D pointC = (Vector3D)(A + (float)desiredDistance * (B - A));
I'm unsure if this is what you would need but is it possible to create a method within your Point3D class to allow subtraction/addition?
(Just guessing the Point3D class as simply as it could be)Something like
public class Point3D
{
public double X,Y,Z
public void ChangeCord(Point3D point)
{
X =- point.X;
Y =- point.Y;
Z =- point.Z;
}
}
So it could just be:
Point3D A = new Point3D { X = 0, Y = 0, Z = 0 };
Point3D B = new Point3D { X = 1, Y = 1, Z = 1 };
Double distanceToAdjust = 0.5;
Point3D newCoordinate = B.ChangeCord(new Point3d{ X = 0.5, Y = 0.5, Z = 0.5 });

Hough with AForge on Kinect. How can i get the right lines?

i want to use my kinect to recognise certain objects. One of the methods that i want to use is the Houghtransformation. To do this i am using the AForge library.
But the lines that i find, are totally wrong. Important ones are missing and there are many useless lines in the picture.
To take care of this problem i thought:
First i am detecting the 100 most intense lines via hough to be sure that all the correct lines are detected as well.
I am writing all points from edge detection into a list and them I am checking for each line whether the detected line is at least on X points ( I used 15, 50 and 150) but nontheless my results are bad.
Have you got any idea, how i can find the right lines, before drawing them into the picture and analysing the geometry any further? Or maybe there is just a grave mistake in my code, that i dont see.
SobelEdgeDetector Kante = new SobelEdgeDetector();
System.Drawing.Bitmap neu2 = Kante.Apply(neu1);
neu2.Save("test.png");
for (int a = 0; a < 320; a++) //alle mögliche Kantenpunkte in eine Liste
{
for (int b = 0; b < 240; b++)
{
color = neu2.GetPixel(a, b);
if ((color.R+color.G+color.B)/3 >= 50)
{
Kantenpunkte.Add(new System.Drawing.Point(a, b));
}
}
}
Bitmap Hough = new Bitmap(320, 240);
Hough.Save("C:\\Users\\Nikolas Rieble\\Desktop\\Hough.png");
//houghtrans
HoughLineTransformation lineTransform = new HoughLineTransformation();
// apply Hough line transofrm
lineTransform.ProcessImage(neu2);
Bitmap houghLineImage = lineTransform.ToBitmap();
houghLineImage.Save("1.png");
// get most intensive lines
HoughLine[] lines = lineTransform.GetMostIntensiveLines(100);
UnmanagedImage fertig = UnmanagedImage.FromManagedImage(neu2);
foreach (HoughLine line in lines)
{
// get line's radius and theta values
int r = line.Radius;
double t = line.Theta;
// check if line is in lower part of the image
if (r < 0)
{
t += 180;
r = -r;
}
// convert degrees to radians
t = (t / 180) * Math.PI;
// get image centers (all coordinate are measured relative
// to center)
int w2 = neu2.Width / 2;
int h2 = neu2.Height / 2;
double x0 = 0, x1 = 0, y0 = 0, y1 = 0;
if (line.Theta != 0)
{
// none-vertical line
x0 = -w2; // most left point
x1 = w2; // most right point
// calculate corresponding y values
y0 = (-Math.Cos(t) * x0 + r) / Math.Sin(t);
y1 = (-Math.Cos(t) * x1 + r) / Math.Sin(t);
}
else
{
// vertical line
x0 = line.Radius;
x1 = line.Radius;
y0 = h2;
y1 = -h2;
}
// draw line on the image
int a = 0;
foreach (System.Drawing.Point p in Kantenpunkte) //count number of detected edge points that are on this line
{
double m1 = ((double)p.Y - y0)/((double)p.X - x0);
double m2 = ((y0 - y1)) / (x0 - x1);
if (m1-m2<0.0001)
{
a=a+1;
}
}
if (a > 150) //only draw lines, which cover at least A points
{
AForge.Imaging.Drawing.Line(fertig,
new IntPoint((int)x0 + w2, h2 - (int)y0),
new IntPoint((int)x1 + w2, h2 - (int)y1),
System.Drawing.Color.Red);
}
}

Categories