Can someone explain how to check if one rotated rectangle intersect other rectangle?
For each edge in both polygons, check if it can be used as a separating line. If so, you are done: No intersection.
If no separation line was found, you have an intersection.
/// Checks if the two polygons are intersecting.
bool IsPolygonsIntersecting(Polygon a, Polygon b)
{
foreach (var polygon in new[] { a, b })
{
for (int i1 = 0; i1 < polygon.Points.Count; i1++)
{
int i2 = (i1 + 1) % polygon.Points.Count;
var p1 = polygon.Points[i1];
var p2 = polygon.Points[i2];
var normal = new Point(p2.Y - p1.Y, p1.X - p2.X);
double? minA = null, maxA = null;
foreach (var p in a.Points)
{
var projected = normal.X * p.X + normal.Y * p.Y;
if (minA == null || projected < minA)
minA = projected;
if (maxA == null || projected > maxA)
maxA = projected;
}
double? minB = null, maxB = null;
foreach (var p in b.Points)
{
var projected = normal.X * p.X + normal.Y * p.Y;
if (minB == null || projected < minB)
minB = projected;
if (maxB == null || projected > maxB)
maxB = projected;
}
if (maxA < minB || maxB < minA)
return false;
}
}
return true;
}
For more information, see this article: 2D Polygon Collision Detection - Code Project
NB: The algorithm only works for convex polygons, specified in either clockwise, or counterclockwise order.
In javascript, the exact same algorithm is (for convenience):
/**
* Helper function to determine whether there is an intersection between the two polygons described
* by the lists of vertices. Uses the Separating Axis Theorem
*
* #param a an array of connected points [{x:, y:}, {x:, y:},...] that form a closed polygon
* #param b an array of connected points [{x:, y:}, {x:, y:},...] that form a closed polygon
* #return true if there is any intersection between the 2 polygons, false otherwise
*/
function doPolygonsIntersect (a, b) {
var polygons = [a, b];
var minA, maxA, projected, i, i1, j, minB, maxB;
for (i = 0; i < polygons.length; i++) {
// for each polygon, look at each edge of the polygon, and determine if it separates
// the two shapes
var polygon = polygons[i];
for (i1 = 0; i1 < polygon.length; i1++) {
// grab 2 vertices to create an edge
var i2 = (i1 + 1) % polygon.length;
var p1 = polygon[i1];
var p2 = polygon[i2];
// find the line perpendicular to this edge
var normal = { x: p2.y - p1.y, y: p1.x - p2.x };
minA = maxA = undefined;
// for each vertex in the first shape, project it onto the line perpendicular to the edge
// and keep track of the min and max of these values
for (j = 0; j < a.length; j++) {
projected = normal.x * a[j].x + normal.y * a[j].y;
if (isUndefined(minA) || projected < minA) {
minA = projected;
}
if (isUndefined(maxA) || projected > maxA) {
maxA = projected;
}
}
// for each vertex in the second shape, project it onto the line perpendicular to the edge
// and keep track of the min and max of these values
minB = maxB = undefined;
for (j = 0; j < b.length; j++) {
projected = normal.x * b[j].x + normal.y * b[j].y;
if (isUndefined(minB) || projected < minB) {
minB = projected;
}
if (isUndefined(maxB) || projected > maxB) {
maxB = projected;
}
}
// if there is no overlap between the projects, the edge we are looking at separates the two
// polygons, and we know there is no overlap
if (maxA < minB || maxB < minA) {
CONSOLE("polygons don't intersect!");
return false;
}
}
}
return true;
};
Hope this helps someone.
Here's the same algorithm in Java if anybody is interested.
boolean isPolygonsIntersecting(Polygon a, Polygon b)
{
for (int x=0; x<2; x++)
{
Polygon polygon = (x==0) ? a : b;
for (int i1=0; i1<polygon.getPoints().length; i1++)
{
int i2 = (i1 + 1) % polygon.getPoints().length;
Point p1 = polygon.getPoints()[i1];
Point p2 = polygon.getPoints()[i2];
Point normal = new Point(p2.y - p1.y, p1.x - p2.x);
double minA = Double.POSITIVE_INFINITY;
double maxA = Double.NEGATIVE_INFINITY;
for (Point p : a.getPoints())
{
double projected = normal.x * p.x + normal.y * p.y;
if (projected < minA)
minA = projected;
if (projected > maxA)
maxA = projected;
}
double minB = Double.POSITIVE_INFINITY;
double maxB = Double.NEGATIVE_INFINITY;
for (Point p : b.getPoints())
{
double projected = normal.x * p.x + normal.y * p.y;
if (projected < minB)
minB = projected;
if (projected > maxB)
maxB = projected;
}
if (maxA < minB || maxB < minA)
return false;
}
}
return true;
}
Check out the method designed by Oren Becker to detect intersection of rotated rectangles with form:
struct _Vector2D
{
float x, y;
};
// C:center; S: size (w,h); ang: in radians,
// rotate the plane by [-ang] to make the second rectangle axis in C aligned (vertical)
struct _RotRect
{
_Vector2D C;
_Vector2D S;
float ang;
};
And calling the following function will return whether two rotated rectangles intersect or not:
// Rotated Rectangles Collision Detection, Oren Becker, 2001
bool check_two_rotated_rects_intersect(_RotRect * rr1, _RotRect * rr2)
{
_Vector2D A, B, // vertices of the rotated rr2
C, // center of rr2
BL, TR; // vertices of rr2 (bottom-left, top-right)
float ang = rr1->ang - rr2->ang, // orientation of rotated rr1
cosa = cos(ang), // precalculated trigonometic -
sina = sin(ang); // - values for repeated use
float t, x, a; // temporary variables for various uses
float dx; // deltaX for linear equations
float ext1, ext2; // min/max vertical values
// move rr2 to make rr1 cannonic
C = rr2->C;
SubVectors2D(&C, &rr1->C);
// rotate rr2 clockwise by rr2->ang to make rr2 axis-aligned
RotateVector2DClockwise(&C, rr2->ang);
// calculate vertices of (moved and axis-aligned := 'ma') rr2
BL = TR = C;
/*SubVectors2D(&BL, &rr2->S);
AddVectors2D(&TR, &rr2->S);*/
//-----------------------------------
BL.x -= rr2->S.x/2; BL.y -= rr2->S.y/2;
TR.x += rr2->S.x/2; TR.y += rr2->S.y/2;
// calculate vertices of (rotated := 'r') rr1
A.x = -(rr1->S.y/2)*sina; B.x = A.x; t = (rr1->S.x/2)*cosa; A.x += t; B.x -= t;
A.y = (rr1->S.y/2)*cosa; B.y = A.y; t = (rr1->S.x/2)*sina; A.y += t; B.y -= t;
//---------------------------------------
//// calculate vertices of (rotated := 'r') rr1
//A.x = -rr1->S.y*sina; B.x = A.x; t = rr1->S.x*cosa; A.x += t; B.x -= t;
//A.y = rr1->S.y*cosa; B.y = A.y; t = rr1->S.x*sina; A.y += t; B.y -= t;
t = sina*cosa;
// verify that A is vertical min/max, B is horizontal min/max
if (t < 0)
{
t = A.x; A.x = B.x; B.x = t;
t = A.y; A.y = B.y; B.y = t;
}
// verify that B is horizontal minimum (leftest-vertex)
if (sina < 0) { B.x = -B.x; B.y = -B.y; }
// if rr2(ma) isn't in the horizontal range of
// colliding with rr1(r), collision is impossible
if (B.x > TR.x || B.x > -BL.x) return 0;
// if rr1(r) is axis-aligned, vertical min/max are easy to get
if (t == 0) {ext1 = A.y; ext2 = -ext1; }
// else, find vertical min/max in the range [BL.x, TR.x]
else
{
x = BL.x-A.x; a = TR.x-A.x;
ext1 = A.y;
// if the first vertical min/max isn't in (BL.x, TR.x), then
// find the vertical min/max on BL.x or on TR.x
if (a*x > 0)
{
dx = A.x;
if (x < 0) { dx -= B.x; ext1 -= B.y; x = a; }
else { dx += B.x; ext1 += B.y; }
ext1 *= x; ext1 /= dx; ext1 += A.y;
}
x = BL.x+A.x; a = TR.x+A.x;
ext2 = -A.y;
// if the second vertical min/max isn't in (BL.x, TR.x), then
// find the local vertical min/max on BL.x or on TR.x
if (a*x > 0)
{
dx = -A.x;
if (x < 0) { dx -= B.x; ext2 -= B.y; x = a; }
else { dx += B.x; ext2 += B.y; }
ext2 *= x; ext2 /= dx; ext2 -= A.y;
}
}
// check whether rr2(ma) is in the vertical range of colliding with rr1(r)
// (for the horizontal range of rr2)
return !((ext1 < BL.y && ext2 < BL.y) ||
(ext1 > TR.y && ext2 > TR.y));
}
inline void AddVectors2D(_Vector2D * v1, _Vector2D * v2)
{
v1->x += v2->x; v1->y += v2->y;
}
inline void SubVectors2D(_Vector2D * v1, _Vector2D * v2)
{
v1->x -= v2->x; v1->y -= v2->y;
}
inline void RotateVector2DClockwise(_Vector2D * v, float ang)
{
float t, cosa = cos(ang), sina = sin(ang);
t = v->x;
v->x = t*cosa + v->y*sina;
v->y = -t*sina + v->y*cosa;
}
In Python:
def do_polygons_intersect(a, b):
"""
* Helper function to determine whether there is an intersection between the two polygons described
* by the lists of vertices. Uses the Separating Axis Theorem
*
* #param a an ndarray of connected points [[x_1, y_1], [x_2, y_2],...] that form a closed polygon
* #param b an ndarray of connected points [[x_1, y_1], [x_2, y_2],...] that form a closed polygon
* #return true if there is any intersection between the 2 polygons, false otherwise
"""
polygons = [a, b];
minA, maxA, projected, i, i1, j, minB, maxB = None, None, None, None, None, None, None, None
for i in range(len(polygons)):
# for each polygon, look at each edge of the polygon, and determine if it separates
# the two shapes
polygon = polygons[i];
for i1 in range(len(polygon)):
# grab 2 vertices to create an edge
i2 = (i1 + 1) % len(polygon);
p1 = polygon[i1];
p2 = polygon[i2];
# find the line perpendicular to this edge
normal = { 'x': p2[1] - p1[1], 'y': p1[0] - p2[0] };
minA, maxA = None, None
# for each vertex in the first shape, project it onto the line perpendicular to the edge
# and keep track of the min and max of these values
for j in range(len(a)):
projected = normal['x'] * a[j][0] + normal['y'] * a[j][1];
if (minA is None) or (projected < minA):
minA = projected
if (maxA is None) or (projected > maxA):
maxA = projected
# for each vertex in the second shape, project it onto the line perpendicular to the edge
# and keep track of the min and max of these values
minB, maxB = None, None
for j in range(len(b)):
projected = normal['x'] * b[j][0] + normal['y'] * b[j][1]
if (minB is None) or (projected < minB):
minB = projected
if (maxB is None) or (projected > maxB):
maxB = projected
# if there is no overlap between the projects, the edge we are looking at separates the two
# polygons, and we know there is no overlap
if (maxA < minB) or (maxB < minA):
print("polygons don't intersect!")
return False;
return True
Maybe it will help someone. The same algorithm in PHP:
function isPolygonsIntersecting($a, $b) {
$polygons = array($a, $b);
for ($i = 0; $i < count($polygons); $i++) {
$polygon = $polygons[$i];
for ($i1 = 0; $i1 < count($polygon); $i1++) {
$i2 = ($i1 + 1) % count($polygon);
$p1 = $polygon[$i1];
$p2 = $polygon[$i2];
$normal = array(
"x" => $p2["y"] - $p1["y"],
"y" => $p1["x"] - $p2["x"]
);
$minA = NULL; $maxA = NULL;
for ($j = 0; $j < count($a); $j++) {
$projected = $normal["x"] * $a[$j]["x"] + $normal["y"] * $a[$j]["y"];
if (!isset($minA) || $projected < $minA) {
$minA = $projected;
}
if (!isset($maxA) || $projected > $maxA) {
$maxA = $projected;
}
}
$minB = NULL; $maxB = NULL;
for ($j = 0; $j < count($b); $j++) {
$projected = $normal["x"] * $b[$j]["x"] + $normal["y"] * $b[$j]["y"];
if (!isset($minB) || $projected < $minB) {
$minB = $projected;
}
if (!isset($maxB) || $projected > $maxB) {
$maxB = $projected;
}
}
if ($maxA < $minB || $maxB < $minA) {
return false;
}
}
}
return true;
}
You can also use Rect.IntersectsWith().
For example, in WPF if you have two UIElements, with RenderTransform and placed on a Canvas, and you want to find out if they intersect you can use something similar:
bool IsIntersecting(UIElement element1, UIElement element2)
{
Rect area1 = new Rect(
(double)element1.GetValue(Canvas.TopProperty),
(double)element1.GetValue(Canvas.LeftProperty),
(double)element1.GetValue(Canvas.WidthProperty),
(double)element1.GetValue(Canvas.HeightProperty));
Rect area2 = new Rect(
(double)element2.GetValue(Canvas.TopProperty),
(double)element2.GetValue(Canvas.LeftProperty),
(double)element2.GetValue(Canvas.WidthProperty),
(double)element2.GetValue(Canvas.HeightProperty));
Transform transform1 = element1.RenderTransform as Transform;
Transform transform2 = element2.RenderTransform as Transform;
if (transform1 != null)
{
area1.Transform(transform1.Value);
}
if (transform2 != null)
{
area2.Transform(transform2.Value);
}
return area1.IntersectsWith(area2);
}
A Type(Java)Script implementation with a toggle to (ex)include "Touch" situations:
class Position {
private _x: number;
private _y: number;
public constructor(x: number = null, y: number = null) {
this._x = x;
this._y = y;
}
public get x() { return this._x; }
public set x(value: number) { this._x = value; }
public get y() { return this._y; }
public set y(value: number) { this._y = value; }
}
class Polygon {
private _positions: Array<Position>;
public constructor(positions: Array<Position> = null) {
this._positions = positions;
}
public addPosition(position: Position) {
if (!position) {
return;
}
if (!this._positions) {
this._positions = new Array<Position>();
}
this._positions.push(position);
}
public get positions(): ReadonlyArray<Position> { return this._positions; }
/**
* https://stackoverflow.com/a/12414951/468910
*
* Helper function to determine whether there is an intersection between the two polygons described
* by the lists of vertices. Uses the Separating Axis Theorem
*
* #param polygonToCompare a polygon to compare with
* #param allowTouch consider it an intersection when polygons only "touch"
* #return true if there is any intersection between the 2 polygons, false otherwise
*/
public isIntersecting(polygonToCompare: Polygon, allowTouch: boolean = true): boolean {
const polygons: Array<ReadonlyArray<Position>> = [this.positions, polygonToCompare.positions]
const firstPolygonPositions: ReadonlyArray<Position> = polygons[0];
const secondPolygonPositions: ReadonlyArray<Position> = polygons[1];
let minA, maxA, projected, i, i1, j, minB, maxB;
for (i = 0; i < polygons.length; i++) {
// for each polygon, look at each edge of the polygon, and determine if it separates
// the two shapes
const polygon = polygons[i];
for (i1 = 0; i1 < polygon.length; i1++) {
// grab 2 vertices to create an edge
const i2 = (i1 + 1) % polygon.length;
const p1 = polygon[i1];
const p2 = polygon[i2];
// find the line perpendicular to this edge
const normal = {
x: p2.y - p1.y,
y: p1.x - p2.x
};
minA = maxA = undefined;
// for each vertex in the first shape, project it onto the line perpendicular to the edge
// and keep track of the min and max of these values
for (j = 0; j < firstPolygonPositions.length; j++) {
projected = normal.x * firstPolygonPositions[j].x + normal.y * firstPolygonPositions[j].y;
if (!minA || projected < minA || (!allowTouch && projected === minA)) {
minA = projected;
}
if (!maxA || projected > maxA || (!allowTouch && projected === maxA)) {
maxA = projected;
}
}
// for each vertex in the second shape, project it onto the line perpendicular to the edge
// and keep track of the min and max of these values
minB = maxB = undefined;
for (j = 0; j < secondPolygonPositions.length; j++) {
projected = normal.x * secondPolygonPositions[j].x + normal.y * secondPolygonPositions[j].y;
if (!minB || projected < minB || (!allowTouch && projected === minB)) {
minB = projected;
}
if (!maxB || projected > maxB || (!allowTouch && projected === maxB)) {
maxB = projected;
}
}
// if there is no overlap between the projects, the edge we are looking at separates the two
// polygons, and we know there is no overlap
if (maxA < minB || (!allowTouch && maxA === minB) || maxB < minA || (!allowTouch && maxB === minA)) {
return false;
}
}
}
return true;
}
Lua implementation built in love2d framework. Collision detection function works in pure lua anyway
math.inf = 1e309
function love.load()
pol = {{0, 0}, {30, 2}, {8, 30}}
pol2 = {{60, 60}, {90, 61}, {98, 100}, {80, 100}}
end
function love.draw()
for k,v in ipairs(pol) do
love.graphics.line(pol[k][1], pol[k][2], pol[k % #pol + 1][1], pol[k % #pol + 1][2])
end
for k,v in ipairs(pol2) do
love.graphics.line(pol2[k][1], pol2[k][2], pol2[k % #pol2 + 1][1], pol2[k % #pol2 + 1][2])
end
end
function love.update(dt)
pol[1][1] = love.mouse.getX()
pol[1][2] = love.mouse.getY()
pol[2][1] = pol[1][1] + 30
pol[2][2] = pol[1][2] + 2
pol[3][1] = pol[1][1] + 8
pol[3][2] = pol[1][2] + 30
--lazy way to see that's function works
print(doPolygonsIntersect(pol, pol2))
end
-------------------------------------------------------------------------
function doPolygonsIntersect(a,b)
polygons = {a,b}
for i=1, #polygons do
polygon = polygons[i]
for i1=1, #polygon do
i2 = i1 % #polygon + 1
p1 = polygon[i1]
p2 = polygon[i2]
nx,ny = p2[2] - p1[2], p1[1] - p2[1]
minA = math.inf
maxA = -math.inf
for j=1, #a do
projected = nx * a[j][1] + ny * a[j][2]
if projected < minA then minA = projected end
if projected > maxA then maxA = projected end
end
minB = math.inf
maxB = -math.inf
for j=1, #b do
projected = nx * b[j][1] + ny * b[j][2]
if projected < minB then minB = projected end
if projected > maxB then maxB = projected end
end
if maxA < minB or maxB < minA then return false end
end
end
return true
end
Took Sri's JavaScript and made it work with Phaser 3 Polygons.
/// Checks if the two Phaser 3 polygons are intersecting.
gameScene.doPolygonsIntersect=function(a, b) {
// https://stackoverflow.com/questions/10962379/how-to-check-intersection-between-2-rotated-rectangles#10965077
/**
* Helper function to determine whether there is an intersection between the two polygons described
* by the lists of vertices. Uses the Separating Axis Theorem
*
* #param a an array of connected points [{x:, y:}, {x:, y:},...] that form a closed polygon
* #param b an array of connected points [{x:, y:}, {x:, y:},...] that form a closed polygon
* #return true if there is any intersection between the 2 polygons, false otherwise
*/
var polygons = [a, b];
var minA, maxA, projected, i, i1, j, minB, maxB;
for (i = 0; i < polygons.length; i++) {
// for each polygon, look at each edge of the polygon, and determine if it separates
// the two shapes
var polygon = polygons[i];
for (i1 = 0; i1 < polygon.points.length; i1++) {
// grab 2 vertices to create an edge
var i2 = (i1 + 1) % polygon.points.length;
var p1 = polygon.points[i1];
var p2 = polygon.points[i2];
// find the line perpendicular to this edge
var normal = { x: p2.y - p1.y, y: p1.x - p2.x };
minA = maxA = undefined;
// for each vertex in the first shape, project it onto the line perpendicular to the edge
// and keep track of the min and max of these values
for (j = 0; j < a.points.length; j++) {
projected = normal.x * a.points[j].x + normal.y * a.points[j].y;
if (!isDef(minA) || projected < minA) {
minA = projected;
}
if (!isDef(maxA) || projected > maxA) {
maxA = projected;
}
}
// for each vertex in the second shape, project it onto the line perpendicular to the edge
// and keep track of the min and max of these values
minB = maxB = undefined;
for (j = 0; j < b.points.length; j++) {
projected = normal.x * b.points[j].x + normal.y * b.points[j].y;
if (!isDef(minB) || projected < minB) {
minB = projected;
}
if (!isDef(maxB) || projected > maxB) {
maxB = projected;
}
}
// if there is no overlap between the projects, the edge we are looking at separates the two
// polygons, and we know there is no overlap
if (maxA < minB || maxB < minA) {
console.log("polygons don't intersect!");
return false;
}
}
}
return true;
};
Here it is in LUA, hope it will help somebody when they need it:
function doPolygonsIntersect(a, b)
local polygons = { a, b };
local minA, maxA, projected, i, i1, j, minB, maxB;
for i = 1, #polygons do
--// for each polygon, look at each edge of the polygon, and determine if it separates
--// the two shapes
local polygon = polygons[i];
for i1 = 0, (#polygon-1) do
--// grab 2 vertices to create an edge
local i2 = (i1 + 1) % (#polygon);
local p1 = polygon[i1+1];
local p2 = polygon[i2+1];
--// find the line perpendicular to this edge
local normal = { x = p2.y - p1.y, y = p1.x - p2.x };
minA = nil;
maxA = nil;
--// for each vertex in the first shape, project it onto the line perpendicular to the edge
--// and keep track of the min and max of these values
for j = 1, #a do
projected = normal.x * a[j].x + normal.y * a[j].y;
if (minA == nil or projected < minA) then
minA = projected;
end
if (maxA == nil or projected > maxA) then
maxA = projected;
end
end
--// for each vertex in the second shape, project it onto the line perpendicular to the edge
--// and keep track of the min and max of these values
minB = nil;
maxB = nil;
for j = 1, #b do
projected = normal.x * b[j].x + normal.y * b[j].y;
if (minB == nil or projected < minB) then
minB = projected;
end
if (maxB == nil or projected > maxB) then
maxB = projected;
end
end
if (maxA < minB or maxB < minA) then
return false;
end
end
end
return true;
end
The accepted algorithm in Go.
func isPolygonIntersecting(a *Polygon, b *Polygon) bool {
for _, polygon := range []*Polygon{a, b} {
for i1 := 0; i1 < len(*polygon); i1++ {
i2 := (i1 + 1) % len(*polygon)
p1 := (*polygon)[i1]
p2 := (*polygon)[i2]
normal := pixel.V(p2.Y-p1.Y, p1.X-p2.X)
minA := math.MaxFloat64
maxA := math.MaxFloat64
for _, p := range *a {
projected := normal.X*p.X + normal.Y*p.Y
if minA == math.MaxFloat64 || projected < minA {
minA = projected
}
if maxA == math.MaxFloat64 || projected > maxA {
maxA = projected
}
}
minB := math.MaxFloat64
maxB := math.MaxFloat64
for _, p := range *b {
projected := normal.X*p.X + normal.Y*p.Y
if minB == math.MaxFloat64 || projected < minB {
minB = projected
}
if maxB == math.MaxFloat64 || projected > maxB {
maxB = projected
}
}
if maxA < minB || maxB < minA {
return false
}
}
}
return true
}
type Polygon []struct {
X float64
Y float64
}
Matlab implementation:
function isIntersecting = IsPolygonsIntersecting(polyVertices1, polyVertices2)
isIntersecting = ...
IsPolygon1Intersecting2( polyVertices1, polyVertices2 ) && ...
IsPolygon1Intersecting2( polyVertices2, polyVertices1 );
end
function isIntersecting = IsPolygon1Intersecting2(polyVertices1,polyVertices2)
nVertices = size(polyVertices1,1);
isIntersecting = true;
for i1 = 1:nVertices
% Current edge vertices:
i2 = mod(i1, nVertices) + 1;
p1 = polyVertices1(i1,:);
p2 = polyVertices1(i2,:);
% Project the polygon vertices on the edge normal and find the extreme values:
normal = [p2(2) - p1(2); p1(1) - p2(1)];
minA = min(polyVertices1 * normal);
maxA = max(polyVertices1 * normal);
minB = min(polyVertices2 * normal);
maxB = max(polyVertices2 * normal);
if (maxA < minB || maxB < minA)
isIntersecting = false;
return;
end
end
end
#dabs's answer https://stackoverflow.com/a/56962827/11846040 converted to Dart:
// `CustomPoint` is just a class holding two x/y or y/x values
class Polygon {
final CustomPoint<num> nw;
final CustomPoint<num> ne;
final CustomPoint<num> se;
final CustomPoint<num> sw;
Polygon(this.nw, this.ne, this.se, this.sw);
List<CustomPoint<num>> get points => [nw, ne, se, sw];
}
bool overlap(Polygon a, Polygon b) {
for (int x = 0; x < 2; x++) {
final Polygon polygon = (x == 0) ? a : b;
for (int i1 = 0; i1 < polygon.points.length; i1++) {
final int i2 = (i1 + 1) % polygon.points.length;
final CustomPoint<num> p1 = polygon.points[i1];
final CustomPoint<num> p2 = polygon.points[i2];
final CustomPoint<num> normal =
CustomPoint<num>(p2.y - p1.y, p1.x - p2.x);
double minA = double.infinity;
double maxA = double.negativeInfinity;
for (CustomPoint<num> p in a.points) {
final num projected = normal.x * p.x + normal.y * p.y;
if (projected < minA) minA = projected.toDouble();
if (projected > maxA) maxA = projected.toDouble();
}
double minB = double.infinity;
double maxB = double.negativeInfinity;
for (CustomPoint<num> p in b.points) {
final num projected = normal.x * p.x + normal.y * p.y;
if (projected < minB) minB = projected.toDouble();
if (projected > maxB) maxB = projected.toDouble();
}
if (maxA < minB || maxB < minA) return false;
}
}
return true;
}
I searched for months to find this answer, but couldn't find it. Enjoy your gift, whoever's looking at this in 15 years time!
Related
So, for each star, i compare this one to all other stars to calculate his speed, velocity, etc.
But that didn't work, I'm not too strong in maths and I think my formula is maybe wrong? idk why that didn't work here my code :
//for each star I compare to all other stars
for(let i = 0; i < pos.length; i ++) {
for (let j = 0; j < pos.length; j ++){
if (i !== j){
// Formula part
const vector = compute_interaction(pos[i], pos[j], 1.0);
accelerations[i].x += vector.x;
accelerations[i].y += vector.y;
accelerations[i].z += vector.z;
break;
}
}
}
for (let i = 0 ; i<accelerations.length ; i++){
speedStars[i].x += accelerations[i].x * 0.001;
speedStars[i].y += accelerations[i].y * 0.001;
speedStars[i].z += accelerations[i].z * 0.001;
}
for (let i = 0 ; i<speedStars.length ; i++){
const i3 = i*3;
starsPositions[i3] += speedStars[i].x * 0.001;
starsPositions[i3 + 1] += speedStars[i].y * 0.001;
starsPositions[i3 + 2] += speedStars[i].z * 0.001;
}
function compute_interaction(currentPosition, positionOtherStar, smoothing_length)
{
const vector = new THREE.Vector3(positionOtherStar.x - currentPosition.x, positionOtherStar.y - currentPosition.y, positionOtherStar.z - currentPosition.z).normalize();
let x = vector.x / (Math.pow(positionOtherStar.x,2.0) - Math.pow(currentPosition.x,2.0)+ smoothing_length)
let y = vector.y / (Math.pow(positionOtherStar.y,2.0) - Math.pow(currentPosition.y,2.0)+ smoothing_length)
let z = vector.z / (Math.pow(positionOtherStar.z,2.0) - Math.pow(currentPosition.z,2.0)+ smoothing_length)
return new THREE.Vector3(x, y, z);
}
Here the CodePen: https://codepen.io/n0rvel/pen/ExEXbYN?editors=0010
Here is the formula/code logic I found on one OpenCL program that works:
Probably, the compute_interaction() function should be:
function compute_interaction(currentPosition, positionOtherStar, smoothing_length)
{
//const vector = new THREE.Vector3(positionOtherStar.x - currentPosition.x, positionOtherStar.y - currentPosition.y, positionOtherStar.z - currentPosition.z).normalize();
//let x = vector.x / (Math.pow(positionOtherStar.x,2.0) - Math.pow(currentPosition.x,2.0)+ smoothing_length)
//let y = vector.y / (Math.pow(positionOtherStar.y,2.0) - Math.pow(currentPosition.y,2.0)+ smoothing_length)
//let z = vector.z / (Math.pow(positionOtherStar.z,2.0) - Math.pow(currentPosition.z,2.0)+ smoothing_length)
//return new THREE.Vector3(x, y, z);
const vector = new THREE.Vector3().subVectors(positionOtherStar, currentPosition);
return vector.normalize().divideScalar(vector.lengthSq() + smoothing_length);
}
I'm trying to write a function to check if a circle is contained inside a polygon.
My algorithm is:
if they intersect, return false
if the circle is "outside" of the polygon, return false
return true
by outside, I mean something like this:
I thought about creating a line segment between the center of the circle and the center of the polygon, and if they intersect an edge on the polygon then the circle is outside of the polygon.
But is there another way to do it?
If the centre of the circle is inside the polygon, the circle is either overlapping or inside it.
If any point of the polygon lies on or inside the circle, they are overlapping.
If any line-segment of the polygon is intersecting the circle, they are overlapping.
Otherwise the circle is outside the polygon.
Something like this should work (C++):
#include <iostream>
#include <vector>
#include <cmath>
namespace math
{
struct Point
{
int x;
int y;
};
bool PointInCircle(Point p, Point center, std::size_t radius)
{
return ((p.x - center.x) * (p.x - center.x) + (p.y - center.y) * (p.y - center.y)) < (radius * radius);
}
bool PointOnCircle(Point p, Point center, std::size_t radius)
{
return ((p.x - center.x) * (p.x - center.x) + (p.y - center.y) * (p.y - center.y)) == (radius * radius);
}
bool LineIntersectsCircle(int ax, int by, int c, Point center, std::size_t radius)
{
// radius == distance = touching/tangent
// radius > distance = not intersecting
// radius < distance = intersecting
int distance = (std::abs(ax * center.x + by * center.y + c)) / sqrt(ax * ax + by * by);
return distance <= radius;
}
bool PointInPolygon(Point p, std::vector<Point> poly)
{
bool result = false;
std::size_t j = poly.size();
for (std::size_t i = 0; i < poly.size(); ++i)
{
if (((poly[i].y <= p.y && p.y < poly[j].y) || (poly[j].y <= p.y && p.y < poly[i].y))
&&
p.x < ((poly[j].x - poly[i].x) * (p.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x))
{
result = !result;
}
j = i;
}
return result;
}
bool CircleInsidePolygon(Point center, std::size_t radius, std::vector<Point> poly)
{
// Circle with radius 0 isn't a circle
if (radius == 0)
{
return false;
}
// If the center of the circle is not within the polygon,
// then the circle may overlap, but it'll never be "contained"
// so return false
if (!PointInPolygon(center, poly))
{
return false;
}
for (std::size_t i = 0; i < poly.size(); ++i)
{
// If any point of the polygon is within the circle,
// the circle is not "contained"
// so return false
if (PointInCircle(poly[i], center, radius))
{
return false;
}
}
for (std::size_t i = 0; i < poly.size(); ++i)
{
// If any line-segment of the polygon intersects the circle,
// the circle is not "contained"
// so return false
Point P1 = i == 0 ? poly[0] : poly[i];
Point P2 = i == 0 ? poly[poly.size() - 1] : poly[i + 1];
int X1 = P1.x;
int X2 = P2.x;
int Y1 = P1.y;
int Y2 = P2.y;
int A = Y1 - Y2;
int B = X2 - X1;
int C = (X1 * Y2) - (X2 * Y1);
if (LineIntersectsCircle(A, B, C, center, radius))
{
return false;
}
}
return true;
}
bool CircleOutsidePolygon(Point center, std::size_t radius, std::vector<Point> poly)
{
// Circle with radius 0 isn't a circle
if (radius == 0)
{
return false;
}
// If the center of the circle is within the polygon,
// the circle is not outside of the polygon completely.
// so return false.
if (PointInPolygon(center, poly))
{
return false;
}
for (std::size_t i = 0; i < poly.size(); ++i)
{
// If any point of the polygon is within the circle,
// or any point of the polygon lies on the circle,
// the circle is not outside of the polygon
// so return false.
if (PointInCircle(poly[i], center, radius) || PointOnCircle(poly[i], center, radius))
{
return false;
}
}
for (std::size_t i = 0; i < poly.size(); ++i)
{
// If any line-segment of the polygon intersects the circle,
// the circle is not outside the polygon, it is overlapping,
// so return false
Point P1 = i == 0 ? poly[0] : poly[i];
Point P2 = i == 0 ? poly[poly.size() - 1] : poly[i + 1];
int X1 = P1.x;
int X2 = P2.x;
int Y1 = P1.y;
int Y2 = P2.y;
int A = Y1 - Y2;
int B = X2 - X1;
int C = (X1 * Y2) - (X2 * Y1);
if (LineIntersectsCircle(A, B, C, center, radius))
{
return false;
}
}
return true;
}
}
int main()
{
std::size_t radius = 1;
math::Point p = {-2, -2};
std::vector<math::Point> poly = {
{0, 0},
{100, 0},
{100, 100},
{0, 100}
};
bool is_inside = math::CircleInsidePolygon(p, radius, poly);
bool is_outside = math::CircleOutsidePolygon(p, radius, poly);
bool is_intersecting = !is_inside && !is_outside;
std::cout<<"Circle In Polygon: "<<std::boolalpha<<is_inside<<"\n";
std::cout<<"Circle Outside Polygon: "<<std::boolalpha<<is_outside<<"\n";
std::cout<<"Circle Intersecting Polygon: "<<std::boolalpha<<is_intersecting<<"\n";
return 0;
}
You have a polygon defined by a list of points A0, A1, A2, ..., Ak, and a circle defined by a center C and a radius r.
Possible algorithm:
Find whether the center C is inside the polygon or not;
If C is outside the polygon, return False.
Else, find the point P on the polygon which is closest to the circle center C;
Compare the distance PC with the radius r.
Return the boolean value r < PC.
This leaves us with two sub-problems to solve:
How to find whether point C is inside the polygon;
How to find the closest point on the polygon.
Related questions solving these sub-problems:
Distance from a point to a polygon;
javascript: How can I find closest point on a polygon from a point?;
How can I determine whether a 2D Point is within a Polygon?;
javascript: Check if Point Is Inside A Polygon;
C: Point in polygon algorithm;
python matplotlib: What's the fastest way of checking if a point is inside a polygon in python.
I'm currently working on a pathtracer in c and open cl.
I'm using this algorithm for rendering. The first collision works well, however, from the second collision onwards there is a dark shadow on the lower side of the voxels.
This is the color of the voxel the initial ray hits:
result
This is the color of the voxel that the second ray hits:
result
And this is the result after rendering to a depth of 1000:
result
This is the code I used (openCL):
int cast_ray(Renderer *r, Ray ray, float3 *hitPos, int3 *normal, Material *material) {
int3 voxel = convert_int3(ray.origin);
int3 step = {
(ray.direction.x >= 0) ? 1 : -1,
(ray.direction.y >= 0) ? 1 : -1,
(ray.direction.z >= 0) ? 1 : -1
};
float3 tMax = {
(ray.direction.x != 0) ? (voxel.x + step.x - ray.origin.x) / ray.direction.x : MAXFLOAT,
(ray.direction.y != 0) ? (voxel.y + step.y - ray.origin.y) / ray.direction.y : MAXFLOAT,
(ray.direction.z != 0) ? (voxel.z + step.z - ray.origin.z) / ray.direction.z : MAXFLOAT
};
float3 tDelta = {
(ray.direction.x != 0) ? 1 / ray.direction.x * step.x : MAXFLOAT,
(ray.direction.y != 0) ? 1 / ray.direction.y * step.y : MAXFLOAT,
(ray.direction.z != 0) ? 1 / ray.direction.z * step.z : MAXFLOAT
};
int side;
while(1) {
if(tMax.x < tMax.y) {
if(tMax.x < tMax.z) {
voxel.x += step.x;
tMax.x += tDelta.x;
side = 0;
} else {
voxel.z += step.z;
tMax.z += tDelta.z;
side = 2;
}
} else {
if(tMax.y < tMax.z) {
voxel.y += step.y;
tMax.y += tDelta.y;
side = 1;
} else {
voxel.z += step.z;
tMax.z += tDelta.z;
side = 2;
}
}
if(out_of_scene(r, voxel))
return 0;
MaterialID id = get_material_ID(r, voxel);
if(id == 0)
continue;
*material = get_material(r, id);
switch(side) {
case 0:
hitPos->x = (float)voxel.x;
hitPos->y = ray.origin.y + (hitPos->x - ray.origin.x) * ray.direction.y / ray.direction.x;
hitPos->z = ray.origin.z + (hitPos->x - ray.origin.x) * ray.direction.z / ray.direction.x;
*normal = (int3){-step.x, 0, 0};
break;
case 1:
hitPos->y = (float)voxel.y;
hitPos->x = ray.origin.x + (hitPos->y - ray.origin.y) * ray.direction.x / ray.direction.y;
hitPos->z = ray.origin.z + (hitPos->y - ray.origin.y) * ray.direction.z / ray.direction.y;
*normal = (int3){0, -step.y, 0};
break;
case 2:
hitPos->z = (float)voxel.z;
hitPos->y = ray.origin.y + (hitPos->z - ray.origin.z) * ray.direction.y / ray.direction.z;
hitPos->x = ray.origin.x + (hitPos->z - ray.origin.z) * ray.direction.x / ray.direction.z;
*normal = (int3){0, 0, -step.z};
break;
}
return 1;
}
}
float3 get_color(Renderer *r, Ray ray) {
float3 mask = 1;
float3 color = 0;
int maxDepth = 1000;
for(int i = 0; i < maxDepth; i++) {
float3 hitPos;
int3 iNormal;
Material material;
if(cast_ray(r, ray, &hitPos, &iNormal, &material)) {
float3 fNormal = convert_float3(iNormal);
if(material.type == 1) {
color = mask * material.color;
break;
} else if(material.type == 2) {
float3 direction = fNormal + random_unit_vector(r->rng);
ray = (Ray){hitPos, direction};
mask *= material.color;
} else if(material.type == 3) {
float3 direction = reflection_dir(ray.direction, fNormal) + random_unit_vector(r->rng) * material.fuzzyness;
ray = (Ray){hitPos, direction};
mask = mask * (1 - material.tint) + mask * material.color * material.tint;
}
} else {
color = mask * r->bgColor;
break;
}
// if(i == 1)
// return material.color;
}
return color;
}
I think that the problem is that the new origin of the ray is somehow not correct, but I can't find a way to fix it.
I've been tasked to find the probability of getting a prime number in a Pythagorean triple for a school project, so I tried to code it, but I didn't consider multiples of Pythagorean Triples using Euclid's formula:
(a = m^2 -n^2, b = 2mn, c = m^2 + n^2.).
Ex. 3-4-5 -> 6-8-10.
var primitiveCount = 0;
var m = floor(2), n = floor(1);
var a, b, c;
var ans1, ans2, ans3;
var isPrime = function(value) {
for(var i = 2; i < value; i++) {
if(value % i === 0) {
return false;
}
}
return value > 1;
};
var j=10;
for(var j = 1; j <= 150; j++){
primitiveCount = 0;
m=2;
n=1;
for(var i=0; i < j; i++) {
a = ((Math.pow(m,2))-(Math.pow(n,2)));
b = 2 * n * m;
c = ((Math.pow(m,2))+(Math.pow(n,2)));
if(a<b<c) {
if(Math.pow(a,2) + Math.pow(b,2) === Math.pow(c,2)) {
ans1 = a;
ans2 = b;
ans3 = c;
}
if(isPrime(ans1) || isPrime(ans2) || isPrime(ans3)){
println(ans1 + " " + ans2 + " " + ans3 + " ~");
primitiveCount++;
}else{
println(ans1 + " " + ans2 + " " + ans3);
}
m++;
n++;
}
}
println(primitiveCount + "/" + j);
}
My code creates unique ones, but does not give me the multiples
It is enough to use natural coefficient p
a = p * (m^2 -n^2)
b = p * 2mn
c = p * (m^2 + n^2)
With m>n, m and n coprime and with different parity this method gives all unique triplets.
Conditions together:
p = 1,2,3...
n = 1,2,3...
m = n + 1 + 2 * i, and GCD(m, n) = 1
Seems that your code does not use all values for m, so omits many triplets.
Also use m*m instead of slow pow. Also you don't need to check a^2+b^2=c^2
Given p(0,0), how do I retrieve points{(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1)} which are the perimeter points relative to p offset by 1.
for(x = p.x -1; x <= p.x + 1; x++) {
for(y = p.y -1; y <= p.y + 1; y++) {
// Do some stuff with each p
}
}
Generic code here. Alter for your programming language and how you store the points.