Related
I am trying to trace quadratic bezier curves, placing "markers" at a given step length distance. Tried to do it a naive way:
const p = toPoint(map, points[section + 1]);
const p2 = toPoint(map, points[section]);
const {x: cx, y: cy} = toPoint(map, cp);
const ll1 = toLatLng(map, p),
ll2 = toLatLng(map, p2),
llc = toLatLng(map, { x: cx, y: cy });
const lineLength = quadraticBezierLength(
ll1.lat,
ll1.lng,
llc.lat,
llc.lng,
ll2.lat,
ll2.lng
);
for (let index = 0; index < Math.floor(lineLength / distance); index++) {
const t = distance / lineLength;
const markerPoint = getQuadraticPoint(
t * index,
p.x,
p.y,
cx,
cy,
p2.x,
p2.y
);
const markerLatLng = toLatLng(map, markerPoint);
markers.push(markerLatLng);
}
This approach does not work since the correlation of a quadratic curve between t and L is not linear. I could not find a formula, that would give me a good approximation, so looking at solving this problem using numeric methods [Newton]. One simple option that I am considering is to split the curve into x [for instance 10] times more pieces than needed. After that, using the same quadraticBezierLength() function calculate the distance to each of those points. After this, chose the point so that the length is closest to the distance * index.
This however would be a huge overkill in terms of algorithm complexity. I could probably start comparing points for index + 1 from the subset after/without the point I selected already, thus skipping the beginning of the set. This would lower the complexity some, yet still very inefficient.
Any ideas and/or suggestions?
Ideally, I want a function that would take d - distance along the curve, p0, cp, p1 - three points defining a quadratic bezier curve and return an array of coordinates, implemented with the least complexity possible.
OK I found analytic formula for 2D quadratic bezier curve in here:
Calculate the length of a segment of a quadratic bezier
So the idea is simply binary search the parameter t until analytically obtained arclength matches wanted length...
C++ code:
//---------------------------------------------------------------------------
float x0,x1,x2,y0,y1,y2; // control points
float ax[3],ay[3]; // coefficients
//---------------------------------------------------------------------------
void get_xy(float &x,float &y,float t) // get point on curve from parameter t=<0,1>
{
float tt=t*t;
x=ax[0]+(ax[1]*t)+(ax[2]*tt);
y=ay[0]+(ay[1]*t)+(ay[2]*tt);
}
//---------------------------------------------------------------------------
float get_l_naive(float t) // get arclength from parameter t=<0,1>
{
// naive iteration
float x0,x1,y0,y1,dx,dy,l=0.0,dt=0.001;
get_xy(x1,y1,t);
for (int e=1;e;)
{
t-=dt; if (t<0.0){ e=0; t=0.0; }
x0=x1; y0=y1; get_xy(x1,y1,t);
dx=x1-x0; dy=y1-y0;
l+=sqrt((dx*dx)+(dy*dy));
}
return l;
}
//---------------------------------------------------------------------------
float get_l(float t) // get arclength from parameter t=<0,1>
{
// analytic fomula from: https://stackoverflow.com/a/11857788/2521214
float ax,ay,bx,by,A,B,C,b,c,u,k,cu,cb;
ax=x0-x1-x1+x2;
ay=y0-y1-y1+y2;
bx=x1+x1-x0-x0;
by=y1+y1-y0-y0;
A=4.0*((ax*ax)+(ay*ay));
B=4.0*((ax*bx)+(ay*by));
C= (bx*bx)+(by*by);
b=B/(2.0*A);
c=C/A;
u=t+b;
k=c-(b*b);
cu=sqrt((u*u)+k);
cb=sqrt((b*b)+k);
return 0.5*sqrt(A)*((u*cu)-(b*cb)+(k*log(fabs((u+cu))/(b+cb))));
}
//---------------------------------------------------------------------------
float get_t(float l0) // get parameter t=<0,1> from arclength
{
float t0,t,dt,l;
for (t=0.0,dt=0.5;dt>1e-10;dt*=0.5)
{
t0=t; t+=dt;
l=get_l(t);
if (l>l0) t=t0;
}
return t;
}
//---------------------------------------------------------------------------
void set_coef() // compute coefficients from control points
{
ax[0]= ( x0);
ax[1]= +(2.0*x1)-(2.0*x0);
ax[2]=( x2)-(2.0*x1)+( x0);
ay[0]= ( y0);
ay[1]= +(2.0*y1)-(2.0*y0);
ay[2]=( y2)-(2.0*y1)+( y0);
}
//---------------------------------------------------------------------------
Usage:
set control points x0,y0,...
then you can use t=get_t(wanted_arclength) freely
In case you want to use get_t_naive and or get_xy you have to call set_coef first
In case you want to tweak speed/accuracy you can play with the target accuracy of binsearch currently set to1e-10
Here optimized (merged get_l,get_t functions) version:
//---------------------------------------------------------------------------
float get_t(float l0) // get parameter t=<0,1> from arclength
{
float t0,t,dt,l;
float ax,ay,bx,by,A,B,C,b,c,u,k,cu,cb,cA;
// precompute get_l(t) constants
ax=x0-x1-x1+x2;
ay=y0-y1-y1+y2;
bx=x1+x1-x0-x0;
by=y1+y1-y0-y0;
A=4.0*((ax*ax)+(ay*ay));
B=4.0*((ax*bx)+(ay*by));
C= (bx*bx)+(by*by);
b=B/(2.0*A);
c=C/A;
k=c-(b*b);
cb=sqrt((b*b)+k);
cA=0.5*sqrt(A);
// bin search t so get_l == l0
for (t=0.0,dt=0.5;dt>1e-10;dt*=0.5)
{
t0=t; t+=dt;
// l=get_l(t);
u=t+b; cu=sqrt((u*u)+k);
l=cA*((u*cu)-(b*cb)+(k*log(fabs((u+cu))/(b+cb))));
if (l>l0) t=t0;
}
return t;
}
//---------------------------------------------------------------------------
For now, I came up with the below:
for (let index = 0; index < Math.floor(numFloat * times); index++) {
const t = distance / lineLength / times;
const l1 = toLatLng(map, p), lcp = toLatLng(map, new L.Point(cx, cy));
const lutPoint = getQuadraticPoint(
t * index,
p.x,
p.y,
cx,
cy,
p2.x,
p2.y
);
const lutLatLng = toLatLng(map, lutPoint);
const length = quadraticBezierLength(l1.lat, l1.lng, lcp.lat, lcp.lng, lutLatLng.lat, lutLatLng.lng);
lut.push({t: t * index, length});
}
const lut1 = lut.filter(({length}) => !isNaN(length));
console.log('lookup table:', lut1);
for (let index = 0; index < Math.floor(numFloat); index++) {
const t = distance / lineLength;
// find t closest to distance * index
const markerT = lut1.reduce((a, b) => {
return a.t && Math.abs(b.length - distance * index) < Math.abs(a.length - distance * index) ? b.t : a.t || 0;
});
const markerPoint = getQuadraticPoint(
markerT,
p.x,
p.y,
cx,
cy,
p2.x,
p2.y
);
const markerLatLng = toLatLng(map, markerPoint);
}
I think only that my Bezier curve length is not working as I expected.
function quadraticBezierLength(x1, y1, x2, y2, x3, y3) {
let a, b, c, d, e, u, a1, e1, c1, d1, u1, v1x, v1y;
v1x = x2 * 2;
v1y = y2 * 2;
d = x1 - v1x + x3;
d1 = y1 - v1y + y3;
e = v1x - 2 * x1;
e1 = v1y - 2 * y1;
c1 = a = 4 * (d * d + d1 * d1);
c1 += b = 4 * (d * e + d1 * e1);
c1 += c = e * e + e1 * e1;
c1 = 2 * Math.sqrt(c1);
a1 = 2 * a * (u = Math.sqrt(a));
u1 = b / u;
a = 4 * c * a - b * b;
c = 2 * Math.sqrt(c);
return (
(a1 * c1 + u * b * (c1 - c) + a * Math.log((2 * u + u1 + c1) / (u1 + c))) /
(4 * a1)
);
}
I believe that the full curve length is correct, but the partial length that is being calculated for the lookup table is wrong.
If I am right, you want points at equally spaced points in terms of curvilinear abscissa (rather than in terms of constant Euclidean distance, which would be a very different problem).
Computing the curvilinear abscissa s as a function of the curve parameter t is indeed an option, but that leads you to the resolution of the equation s(t) = Sk/n for integer k, where S is the total length (or s(t) = kd if a step is imposed). This is not convenient because s(t) is not available as a simple function and is transcendental.
A better method is to solve the differential equation
dt/ds = 1/(ds/dt) = 1/√(dx/dt)²+(dy/dt)²
using your preferred ODE solver (RK4). This lets you impose your fixed step on s and is computationally efficient.
I have a robotic arm composed of 2 servo motors. I am trying to calculate inverse kinematics such that the arm is positioned in the middle of a canvas and can move to all possible points in both directions (left and right). This is an image of the system Image. The first servo moves 0-180 (Anti-clockwise). The second servo moves 0-180 (clockwise).
Here is my code:
int L1 = 170;
int L2 = 230;
Vector shoulderV;
Vector targetV;
shoulderV = new Vector(0,0);
targetV = new Vector(0,400);
Vector difference = Vector.Subtract(targetV, shoulderV);
double L3 = difference.Length;
if (L3 > 400) { L3 = 400; }
if (L3 < 170) { L3 = 170; }
// a + b is the equivelant of the shoulder angle
double a = Math.Acos((L1 * L1 + L3 * L3 - L2 * L2) / (2 * L1 * L3));
double b = Math.Atan(difference.Y / difference.X);
// S1 is the shoulder angle
double S1 = a + b;
// S2 is the elbow angle
double S2 = Math.Acos((L1 * L1 + L2 * L2 - L3 * L3) / (2 * L1 * L2));
int shoulderAngle = Convert.ToInt16(Math.Round(S1 * 180 / Math.PI));
if (shoulderAngle < 0) { shoulderAngle = 180 - shoulderAngle; }
if (shoulderAngle > 180) { shoulderAngle = 180; }
int elbowAngle = Convert.ToInt16(Math.Round(S2 * 180 / Math.PI));
elbowAngle = 180 - elbowAngle;
Initially, when the system is first started, the arm is straightened with shoulder=90, elbow =0.
When I give positive x values I get correct results in the left side of the canvas. However, I want the arm to move in the right side as well. I do not get correct values when I enter negatives. What am I doing wrong? Do I need an extra servo to reach points in the right side?
Sorry if the explanation is not good. English is not my first language.
I suspect that you are losing a sign when you are using Math.Atan(). I don't know what programming language or environment this is, but try and see if you have something like this:
Instead of this line:
double b = Math.Atan(difference.Y / difference.X);
Use something like this:
double b = Math.Atan2(difference.Y, difference.X);
When difference.Y and difference.X have the same sign, dividing them results in a positive value. That prevents you from differentiating between the cases when they are both positive and both negative. In that case, you cannot differentiate between 30 and 210 degrees, for example.
Here's the link to the question..
http://www.codechef.com/problems/J7
I figured out that 2 edges have to be equal in order to give the maximum volume, and then used x, x, a*x as the lengths of the three edges to write the equations -
4*x + 4*x + 4*a*x = P (perimeter) and,
2*x^2 + 4*(a*x *x) = S (total area of the box)
so from the first equation I got x in terms of P and a, and then substituted it in the second equation and then got a quadratic equation with the unknown being a. and then I used the greater root of a and got x.
But this method seems to be giving the wrong answer! :|
I know that there isn't any logical error in this. Maybe some formatting error?
Here's the main code that I've written :
{
public static void main(String[] args)
{
TheBestBox box = new TheBestBox();
reader = box.new InputReader(System.in);
writer = box.new OutputWriter(System.out);
getAttributes();
writer.flush();
reader.close();
writer.close();
}
public static void getAttributes()
{
t = reader.nextInt(); // t is the number of test cases in the question
for (int i = 0; i < t; i++)
{
p = reader.nextInt(); // p is the perimeter given as input
area = reader.nextInt(); // area of the whole sheet, given as input
a = findRoot(); // the fraction by which the third side differs by the first two
side = (double) p / (4 * (2 + a)); // length of the first and the second sides (equal)
height = a * side; // assuming that the base is a square, the height has to be the side which differs from the other two
// writer.println(side * side * height);
// System.out.printf("%.2f\n", (side * side * height));
writer.println(String.format("%.2f", (side * side * height))); // just printing out the final answer
}
}
public static double findRoot() // the method to find the 2 possible fractions by which the height can differ from the other two sides and return the bigger one of them
{
double a32, b, discriminant, root1, root2;
a32 = 32 * area - p * p;
b = 32 * area - 2 * p * p;
discriminant = Math.sqrt(b * b - 4 * 8 * area * a32);
double temp;
temp = 2 * 8 * area;
root1 = (- b + discriminant) / temp;
root2 = (- b - discriminant) / temp;
return Math.max(root1, root2);
}
}
could someone please help me out with this? Thank You. :)
I also got stuck in this question and realized that can be done by making equation of V(volume) in terms of one side say 'l' and using differentiation to find maximum volume in terms of any one side 'l'.
So, equations are like this :-
P = 4(l+b+h);
S = 2(l*b+b*h+l*h);
V = l*b*h;
so equation in l for V = (l^3) - (l^2)P/4 + lS/2 -------equ(1)
After differentiation we get:-
d(V)/d(l) = 3*(l^2) - l*P/2 + S/2;
to get max V we need to equate above equation to zero(0) and get the value of l.
So, solutions to a quadratic equation will be:-
l = ( P + sqrt((P^2)-24S) ) / 24;
so substitute this l in equation(1) to get max volume.
I need a algorithm for detecting if a circle has hit a square, and I saw this post:
Circle-Rectangle collision detection (intersection)
It looks like I should go for ShreevatsaR's answer, but I am a math fool, and I have no idea how to finish the algorithm. Could anyone find the time to make a complete example for me please, I have searched the net for this, and have yet found no working example.
Thank you very much
Soeren
EDIT:
Ok here is my attempt. It is not working, it never detects any collisions.
typedef struct {
double x;
double y;
} point;
typedef struct {
point one;
point two;
} segment;
typedef struct {
point center;
double radius;
} circle;
typedef struct {
point p;
int width;
int height;
point a;
point b;
point c;
point d;
} rectangle;
double slope(point one, point two) {
return (double)(one.y-two.y)/(one.x-two.x);
}
double distance(point p, segment s) {
// Line one is the original line that was specified, and line two is
// the line we're constructing that runs through the specified point,
// at a right angle to line one.
//
// if it's a vertical line return the horizontal distance
if ( s.one.x == s.two.x)
return fabs(s.one.x - p.x);
// if it's a horizontal line return the vertical distance
if ( s.one.y == s.two.y )
return fabs(s.one.y - p.y);
// otherwise, find the slope of the line
double m_one = slope(s.one, s.two);
// the other slope is at a right angle.
double m_two = -1.0 / m_one;
// find the y-intercepts.
double b_one = s.one.y - s.one.x * m_one;
double b_two = p.y - p.x * m_two;
// find the point of intersection
double x = (b_two - b_one) / (m_one - m_two);
double y = m_one * x + b_one;
// find the x and y distances
double x_dist = x - p.x;
double y_dist = y - p.y;
// and return the total distance.
return sqrt(x_dist * x_dist + y_dist * y_dist);
}
bool intersectsCircle(segment s, circle c) {
return distance(c.center, s) <= c.radius;
}
bool pointInRectangle(point p, rectangle r)
{
float right = r.p.x + r.width;
float left = r.p.x - r.width;
float top = r.p.y + r.height;
float bottom = r.p.y - r.height;
return ((left <= p.x && p.x <= right) && (top <= p.y && p.y <= bottom));
}
bool intersect(circle c, rectangle r) {
segment ab;
ab.one = r.a;
ab.two = r.b;
segment bc;
ab.one = r.b;
ab.two = r.c;
segment cd;
ab.one = r.c;
ab.two = r.d;
segment da;
ab.one = r.d;
ab.two = r.a;
return pointInRectangle(c.center, r) ||
intersectsCircle(ab, c) ||
intersectsCircle(bc, c) ||
intersectsCircle(cd, c) ||
intersectsCircle(da, c);
}
The primary part he seems to have left is the InteresectsCircle(line, circle).
#include <math.h>
typedef struct {
double x;
double y;
} point;
typedef struct {
point one;
point two;
} segment;
typedef struct {
point center;
double radius;
} circle;
double slope(point &one, point &two) {
return (double)(one.y-two.y)/(one.x-two.x);
}
double distance(point &p, segment &s) {
// Line one is the original line that was specified, and line two is
// the line we're constructing that runs through the specified point,
// at a right angle to line one.
//
// if it's a vertical line return the horizontal distance
if ( s.one.x == s.two.x)
return fabs(s.one.x - p.x);
// if it's a horizontal line return the vertical distance
if ( s.one.y == s.two.y )
return fabs(s.one.y - p.y);
// otherwise, find the slope of the line
double m_one = slope(s.one, s.two);
// the other slope is at a right angle.
double m_two = -1.0 / m_one;
// find the y-intercepts.
double b_one = s.one.y - s.one.x * m_one;
double b_two = p.y - p.x * m_two;
// find the point of intersection
double x = (b_two - b_one) / (m_one - m_two);
double y = m_one * x + b_one;
// find the x and y distances
double x_dist = x - p.x;
double y_dist = y - p.y;
// and return the total distance.
return sqrt(x_dist * x_dist + y_dist * y_dist);
}
bool IntersectsCircle(segment s, circle c) {
return distance(circle.center, s) <= circle.radius;
}
I have some code in C++ (lightly templated) that should do these intersection tests, but I haven't had time to test them yet. In particular, I have the segment-circle intersection test as well as parallelogram-circle intersection, which is supposed to compute the intersection area and intersection points. Again, this is completely untested as of the writing of this comment, so you will need to test/adapt them to your needs.
How to test if a line segment intersects an axis-aligned rectange in 2D? The segment is defined with its two ends: p1, p2. The rectangle is defined with top-left and bottom-right points.
The original poster wanted to DETECT an intersection between a line segment and a polygon. There was no need to LOCATE the intersection, if there is one. If that's how you meant it, you can do less work than Liang-Barsky or Cohen-Sutherland:
Let the segment endpoints be p1=(x1 y1) and p2=(x2 y2).
Let the rectangle's corners be (xBL yBL) and (xTR yTR).
Then all you have to do is
A. Check if all four corners of the rectangle are on the same side of the line.
The implicit equation for a line through p1 and p2 is:
F(x y) = (y2-y1)*x + (x1-x2)*y + (x2*y1-x1*y2)
If F(x y) = 0, (x y) is ON the line.
If F(x y) > 0, (x y) is "above" the line.
If F(x y) < 0, (x y) is "below" the line.
Substitute all four corners into F(x y). If they're all negative or all positive, there is no intersection. If some are positive and some negative, go to step B.
B. Project the endpoint onto the x axis, and check if the segment's shadow intersects the polygon's shadow. Repeat on the y axis:
If (x1 > xTR and x2 > xTR), no intersection (line is to right of rectangle).
If (x1 < xBL and x2 < xBL), no intersection (line is to left of rectangle).
If (y1 > yTR and y2 > yTR), no intersection (line is above rectangle).
If (y1 < yBL and y2 < yBL), no intersection (line is below rectangle).
else, there is an intersection. Do Cohen-Sutherland or whatever code was mentioned in the other answers to your question.
You can, of course, do B first, then A.
Alejo
Wrote quite simple and working solution:
bool SegmentIntersectRectangle(double a_rectangleMinX,
double a_rectangleMinY,
double a_rectangleMaxX,
double a_rectangleMaxY,
double a_p1x,
double a_p1y,
double a_p2x,
double a_p2y)
{
// Find min and max X for the segment
double minX = a_p1x;
double maxX = a_p2x;
if(a_p1x > a_p2x)
{
minX = a_p2x;
maxX = a_p1x;
}
// Find the intersection of the segment's and rectangle's x-projections
if(maxX > a_rectangleMaxX)
{
maxX = a_rectangleMaxX;
}
if(minX < a_rectangleMinX)
{
minX = a_rectangleMinX;
}
if(minX > maxX) // If their projections do not intersect return false
{
return false;
}
// Find corresponding min and max Y for min and max X we found before
double minY = a_p1y;
double maxY = a_p2y;
double dx = a_p2x - a_p1x;
if(Math::Abs(dx) > 0.0000001)
{
double a = (a_p2y - a_p1y) / dx;
double b = a_p1y - a * a_p1x;
minY = a * minX + b;
maxY = a * maxX + b;
}
if(minY > maxY)
{
double tmp = maxY;
maxY = minY;
minY = tmp;
}
// Find the intersection of the segment's and rectangle's y-projections
if(maxY > a_rectangleMaxY)
{
maxY = a_rectangleMaxY;
}
if(minY < a_rectangleMinY)
{
minY = a_rectangleMinY;
}
if(minY > maxY) // If Y-projections do not intersect return false
{
return false;
}
return true;
}
Since your rectangle is aligned, Liang-Barsky might be a good solution. It is faster than Cohen-Sutherland, if speed is significant here.
Siggraph explanation
Another good description
And of course, Wikipedia
You could also create a rectangle out of the segment and test if the other rectangle collides with it, since it is just a series of comparisons. From pygame source:
def _rect_collide(a, b):
return a.x + a.w > b.x and b.x + b.w > a.x and \
a.y + a.h > b.y and b.y + b.h > a.y
Use the Cohen-Sutherland algorithm.
It's used for clipping but can be slightly tweaked for this task. It divides 2D space up into a tic-tac-toe board with your rectangle as the "center square".
then it checks to see which of the nine regions each of your line's two points are in.
If both points are left, right, top, or bottom, you trivially reject.
If either point is inside, you trivially accept.
In the rare remaining cases you can do the math to intersect with whichever sides of the rectangle are possible to intersect with, based on which regions they're in.
Or just use/copy the code already in the Java method
java.awt.geom.Rectangle2D.intersectsLine(double x1, double y1, double x2, double y2)
Here is the method after being converted to static for convenience:
/**
* Code copied from {#link java.awt.geom.Rectangle2D#intersectsLine(double, double, double, double)}
*/
public class RectangleLineIntersectTest {
private static final int OUT_LEFT = 1;
private static final int OUT_TOP = 2;
private static final int OUT_RIGHT = 4;
private static final int OUT_BOTTOM = 8;
private static int outcode(double pX, double pY, double rectX, double rectY, double rectWidth, double rectHeight) {
int out = 0;
if (rectWidth <= 0) {
out |= OUT_LEFT | OUT_RIGHT;
} else if (pX < rectX) {
out |= OUT_LEFT;
} else if (pX > rectX + rectWidth) {
out |= OUT_RIGHT;
}
if (rectHeight <= 0) {
out |= OUT_TOP | OUT_BOTTOM;
} else if (pY < rectY) {
out |= OUT_TOP;
} else if (pY > rectY + rectHeight) {
out |= OUT_BOTTOM;
}
return out;
}
public static boolean intersectsLine(double lineX1, double lineY1, double lineX2, double lineY2, double rectX, double rectY, double rectWidth, double rectHeight) {
int out1, out2;
if ((out2 = outcode(lineX2, lineY2, rectX, rectY, rectWidth, rectHeight)) == 0) {
return true;
}
while ((out1 = outcode(lineX1, lineY1, rectX, rectY, rectWidth, rectHeight)) != 0) {
if ((out1 & out2) != 0) {
return false;
}
if ((out1 & (OUT_LEFT | OUT_RIGHT)) != 0) {
double x = rectX;
if ((out1 & OUT_RIGHT) != 0) {
x += rectWidth;
}
lineY1 = lineY1 + (x - lineX1) * (lineY2 - lineY1) / (lineX2 - lineX1);
lineX1 = x;
} else {
double y = rectY;
if ((out1 & OUT_BOTTOM) != 0) {
y += rectHeight;
}
lineX1 = lineX1 + (y - lineY1) * (lineX2 - lineX1) / (lineY2 - lineY1);
lineY1 = y;
}
}
return true;
}
}
A quick Google search popped up a page with C++ code for testing the intersection.
Basically it tests the intersection between the line, and every border or the rectangle.
Rectangle and line intersection code
Here's a javascript version of #metamal's answer
var isRectangleIntersectedByLine = function (
a_rectangleMinX,
a_rectangleMinY,
a_rectangleMaxX,
a_rectangleMaxY,
a_p1x,
a_p1y,
a_p2x,
a_p2y) {
// Find min and max X for the segment
var minX = a_p1x
var maxX = a_p2x
if (a_p1x > a_p2x) {
minX = a_p2x
maxX = a_p1x
}
// Find the intersection of the segment's and rectangle's x-projections
if (maxX > a_rectangleMaxX)
maxX = a_rectangleMaxX
if (minX < a_rectangleMinX)
minX = a_rectangleMinX
// If their projections do not intersect return false
if (minX > maxX)
return false
// Find corresponding min and max Y for min and max X we found before
var minY = a_p1y
var maxY = a_p2y
var dx = a_p2x - a_p1x
if (Math.abs(dx) > 0.0000001) {
var a = (a_p2y - a_p1y) / dx
var b = a_p1y - a * a_p1x
minY = a * minX + b
maxY = a * maxX + b
}
if (minY > maxY) {
var tmp = maxY
maxY = minY
minY = tmp
}
// Find the intersection of the segment's and rectangle's y-projections
if(maxY > a_rectangleMaxY)
maxY = a_rectangleMaxY
if (minY < a_rectangleMinY)
minY = a_rectangleMinY
// If Y-projections do not intersect return false
if(minY > maxY)
return false
return true
}
I did a little napkin solution..
Next find m and c and hence the equation y = mx + c
y = (Point2.Y - Point1.Y) / (Point2.X - Point1.X)
Substitute P1 co-ordinates to now find c
Now for a rectangle vertex, put the X value in the line equation, get the Y value and see if the Y value lies in the rectangle bounds shown below
(you can find the constant values X1, X2, Y1, Y2 for the rectangle such that)
X1 <= x <= X2 &
Y1 <= y <= Y2
If the Y value satisfies the above condition and lies between (Point1.Y, Point2.Y) - we have an intersection.
Try every vertex if this one fails to make the cut.
I was looking at a similar problem and here's what I came up with. I was first comparing the edges and realized something. If the midpoint of an edge that fell within the opposite axis of the first box is within half the length of that edge of the outer points on the first in the same axis, then there is an intersection of that side somewhere.
But that was thinking 1 dimensionally and required looking at each side of the second box to figure out.
It suddenly occurred to me that if you find the 'midpoint' of the second box and compare the coordinates of the midpoint to see if they fall within 1/2 length of a side (of the second box) of the outer dimensions of the first, then there is an intersection somewhere.
i.e. box 1 is bounded by x1,y1 to x2,y2
box 2 is bounded by a1,b1 to a2,b2
the width and height of box 2 is:
w2 = a2 - a1 (half of that is w2/2)
h2 = b2 - b1 (half of that is h2/2)
the midpoints of box 2 are:
am = a1 + w2/2
bm = b1 + h2/2
So now you just check if
(x1 - w2/2) < am < (x2 + w2/2) and (y1 - h2/2) < bm < (y2 + h2/2)
then the two overlap somewhere.
If you want to check also for edges intersecting to count as 'overlap' then
change the < to <=
Of course you could just as easily compare the other way around (checking midpoints of box1 to be within 1/2 length of the outer dimenions of box 2)
And even more simplification - shift the midpoint by your half lengths and it's identical to the origin point of that box. Which means you can now check just that point for falling within your bounding range and by shifting the plain up and to the left, the lower corner is now the lower corner of the first box. Much less math:
(x1 - w2) < a1 < x2
&&
(y1 - h2) < b1 < y2
[overlap exists]
or non-substituted:
( (x1-(a2-a1)) < a1 < x2 ) && ( (y1-(b2-b1)) < b1 < y2 ) [overlap exists]
( (x1-(a2-a1)) <= a1 <= x2 ) && ( (y1-(b2-b1)) <= b1 <= y2 ) [overlap or intersect exists]
coding example in PHP (I'm using an object model that has methods for things like getLeft(), getRight(), getTop(), getBottom() to get the outer coordinates of a polygon and also has a getWidth() and getHeight() - depending on what parameters were fed it, it will calculate and cache the unknowns - i.e. I can create a polygon with x1,y1 and ... w,h or x2,y2 and it can calculate the others)
I use 'n' to designate the 'new' item being checked for overlap ($nItem is an instance of my polygon object) - the items to be tested again [this is a bin/sort knapsack program] are in an array consisting of more instances of the (same) polygon object.
public function checkForOverlaps(BinPack_Polygon $nItem) {
// grab some local variables for the stuff re-used over and over in loop
$nX = $nItem->getLeft();
$nY = $nItem->getTop();
$nW = $nItem->getWidth();
$nH = $nItem->getHeight();
// loop through the stored polygons checking for overlaps
foreach($this->packed as $_i => $pI) {
if(((($pI->getLeft() - $nW) < $nX) && ($nX < $pI->getRight())) &&
((($pI->getTop() - $nH) < $nY) && ($nY < $pI->getBottom()))) {
return false;
}
}
return true;
}
Some sample code for my solution (in php):
// returns 'true' on overlap checking against an array of similar objects in $this->packed
public function checkForOverlaps(BinPack_Polygon $nItem) {
$nX = $nItem->getLeft();
$nY = $nItem->getTop();
$nW = $nItem->getWidth();
$nH = $nItem->getHeight();
// loop through the stored polygons checking for overlaps
foreach($this->packed as $_i => $pI) {
if(((($pI->getLeft() - $nW) < $nX) && ($nX < $pI->getRight())) && ((($pI->getTop() - $nH) < $nY) && ($nY < $pI->getBottom()))) {
return true;
}
}
return false;
}