Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/RAIRLab/Peirce-My-Heart i…
Browse files Browse the repository at this point in the history
…nto 64-rewrite-with-universal-event-listeners
  • Loading branch information
DawnTheWitch committed Oct 12, 2023
2 parents 72b31e9 + ce71674 commit 70a3433
Show file tree
Hide file tree
Showing 11 changed files with 253 additions and 343 deletions.
48 changes: 25 additions & 23 deletions src/AEG/AEGTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {AtomNode} from "./AtomNode";
import {CutNode} from "./CutNode";
import {Point} from "./Point";
import {Ellipse} from "./Ellipse";
import {shapesOverlap} from "./AEGUtils";

export class AEGTree {
sheet: CutNode;
Expand All @@ -28,24 +29,24 @@ export class AEGTree {
* @returns True, if the structure is structurally consistent. Else, false.
*/
private verifyAEG(currentCut: CutNode): boolean {
for (let i = 0; i < currentCut.Children.length; i++) {
for (let i = 0; i < currentCut.children.length; i++) {
//Check that all children, in this level, are in currentCut
if (!currentCut.containsNode(currentCut.Children[i])) {
if (!currentCut.containsNode(currentCut.children[i])) {
return false;
}

//Check for overlaps on the same level
for (let j = i + 1; j < currentCut.Children.length; j++) {
if (this.overlaps(currentCut.Children[i], currentCut.Children[j])) {
for (let j = i + 1; j < currentCut.children.length; j++) {
if (this.overlaps(currentCut.children[i], currentCut.children[j])) {
return false;
}
}
}
for (let i = 0; i < currentCut.Children.length; i++) {
for (let i = 0; i < currentCut.children.length; i++) {
//Check one level deeper if the child is a CutNode. Recursive case
if (
currentCut.Children[i] instanceof CutNode &&
!this.verifyAEG(currentCut.Children[i] as CutNode)
currentCut.children[i] instanceof CutNode &&
!this.verifyAEG(currentCut.children[i] as CutNode)
) {
return false;
}
Expand All @@ -61,8 +62,8 @@ export class AEGTree {
*/
public canInsert(incomingNode: AtomNode | CutNode): boolean {
const currentCut: CutNode = this.sheet.getCurrentCut(incomingNode);
for (let i = 0; i < currentCut.Children.length; i++) {
if (this.overlaps(incomingNode, currentCut.Children[i])) {
for (let i = 0; i < currentCut.children.length; i++) {
if (this.overlaps(incomingNode, currentCut.children[i])) {
return false;
}
}
Expand All @@ -80,14 +81,14 @@ export class AEGTree {
}

const currentCut: CutNode = this.sheet.getCurrentCut(incomingNode);
const originalChildren: (AtomNode | CutNode)[] = [...currentCut.Children];
currentCut.Child = incomingNode;
const originalChildren: (AtomNode | CutNode)[] = [...currentCut.children];
currentCut.child = incomingNode;

if (incomingNode instanceof CutNode) {
for (let i = 0; i < originalChildren.length; i++) {
for (let i = originalChildren.length - 1; i >= 0; i--) {
if (incomingNode.containsNode(originalChildren[i])) {
incomingNode.Child = originalChildren[i];
currentCut.Children.splice(i, 1);
incomingNode.child = originalChildren[i];
currentCut.children.splice(i, 1);
}
}
}
Expand All @@ -114,24 +115,25 @@ export class AEGTree {

if (incomingNode instanceof AtomNode) {
if (otherNode instanceof AtomNode) {
return (incomingNode as AtomNode).Rectangle.overlaps(
(otherNode as AtomNode).Rectangle
return shapesOverlap(
(incomingNode as AtomNode).rectangle,
(otherNode as AtomNode).rectangle
);
} else {
//the case where otherNode is the sheet is handled in canInsert()
//and all child.ellipse[i] will never be null. this is the reason for ! below

ellipse1 = (otherNode as CutNode).Ellipse!;
return (incomingNode as AtomNode).Rectangle.overlaps(ellipse1);
ellipse1 = (otherNode as CutNode).ellipse!;
return shapesOverlap((incomingNode as AtomNode).rectangle, ellipse1);
}
} else {
if (otherNode instanceof AtomNode) {
ellipse1 = (incomingNode as CutNode).Ellipse!;
return ellipse1.overlaps((otherNode as AtomNode).Rectangle);
ellipse1 = (incomingNode as CutNode).ellipse!;
return shapesOverlap(ellipse1, (otherNode as AtomNode).rectangle);
} else {
ellipse1 = (incomingNode as CutNode).Ellipse!;
ellipse2 = (otherNode as CutNode).Ellipse!;
return ellipse1.overlaps(ellipse2);
ellipse1 = (incomingNode as CutNode).ellipse!;
ellipse2 = (otherNode as CutNode).ellipse!;
return shapesOverlap(ellipse1, ellipse2);
}
}
}
Expand Down
204 changes: 41 additions & 163 deletions src/AEG/AEGUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,25 @@ import {Rectangle} from "./Rectangle";
* @param existingShape The existing shape
* @returns True, if the new shape overlaps the existing shape. Else, false
*/
export function shapesOverlaps(
export function shapesOverlap(
newShape: Rectangle | Ellipse,
existingShape: Rectangle | Ellipse
): boolean {
if (newShape instanceof Rectangle) {
if (existingShape instanceof Rectangle) {
//For rectangle-rectangle, check if their edges intersect
return edgesIntersect(newShape, existingShape);
return edgesWithin(newShape, existingShape) || edgesWithin(existingShape, newShape);
} else {
//For ellipse-rectangle collision, check if points on the ellipse are
//within the rectangle
const points: Point[] = getEllipsePoints(existingShape as Ellipse, 64);
for (let i = 0; i < points.length; i++) {
if (pointInRect(newShape as Rectangle, points[i])) {
return true;
}
}
return false;
return ellipseRectangleCollision(existingShape as Ellipse, newShape as Rectangle);
}
} else {
if (existingShape instanceof Rectangle) {
//For ellipse-rectangle collision, check if points on the ellipse are
//within the rectangle
const points: Point[] = getEllipsePoints(newShape as Ellipse, 64);
for (let i = 0; i < points.length; i++) {
if (pointInRect(existingShape as Rectangle, points[i])) {
return true;
}
}
return false;
return ellipseRectangleCollision(newShape as Ellipse, existingShape as Rectangle);
} else {
//For ellipse-ellipse collision, check if the rectangular bounding boxes intersect.
//If they do, check if points of the new ellipse are within the current ellipse
if (
shapesOverlaps(
shapesOverlap(
(newShape as Ellipse).boundingBox,
(existingShape as Ellipse).boundingBox
) ||
Expand All @@ -54,9 +38,9 @@ export function shapesOverlaps(
//if there is an overlap, check if points along the ellipse curve overlap
//this can be done by checking if points along the curve of this ellipse
//are within the other ellipse
const points: Point[] = getEllipsePoints(newShape, 64);
const points: Point[] = getEllipsePoints(newShape);
for (let i = 0; i < points.length; i++) {
if (pointInELlipse(existingShape as Ellipse, points[i])) {
if (pointInEllipse(existingShape as Ellipse, points[i])) {
return true;
}
}
Expand All @@ -66,6 +50,18 @@ export function shapesOverlaps(
}
}

function ellipseRectangleCollision(ellipse: Ellipse, rectangle: Rectangle): boolean {
//For ellipse-rectangle collision, check if points on the ellipse are
//within the rectangle
const points: Point[] = getEllipsePoints(ellipse);
for (let i = 0; i < points.length; i++) {
if (pointInRect(rectangle, points[i])) {
return true;
}
}
return false;
}

/**
* Method that checks whether a shape is contained within another
* @param outerShape The outer shape
Expand Down Expand Up @@ -104,18 +100,18 @@ export function shapeContains(
//the ellipse
const innerCorners = (innerShape as Rectangle).getCorners();
for (let i = 0; i < 4; i++) {
if (!pointInELlipse(outerShape as Ellipse, innerCorners[i])) {
if (!pointInEllipse(outerShape as Ellipse, innerCorners[i])) {
return false;
}
}
return true;
} else {
//An ellipse contains an ellipse if all the widest coordinates of the inner ellipse
//are within the outer ellipse
const innerCoords: Point[] = getEllipsePoints(innerShape as Ellipse, 64);
const innerCoords: Point[] = getEllipsePoints(innerShape as Ellipse);
//= getWidestCoordinates(innerShape as Ellipse);
for (let i = 0; i < innerCoords.length; i++) {
if (!pointInELlipse(outerShape as Ellipse, innerCoords[i])) {
if (!pointInEllipse(outerShape as Ellipse, innerCoords[i])) {
return false;
}
}
Expand All @@ -125,142 +121,23 @@ export function shapeContains(
}

/**
* Method that checks if any edges of this rectangle overlap with the other rectangle.
* @param otherRect The other rectangle to be checked.
* Method that checks if any edges of a rectangle are within the other rectangle.
* @param rect1 The incoming rectangle.
* @param rect2 The existing rectangle.
* @returns True, if edges overlap. Else, false.
* @todo This algo can and should be simplified to be less than 10 lines of code. -James-Oswald
*/
function edgesIntersect(shape1: Rectangle, shape2: Rectangle): boolean {
const thisCorners = shape1.getCorners();
const otherCorners = shape2.getCorners();
function edgesWithin(rect1: Rectangle, rect2: Rectangle): boolean {
const corners1 = rect1.getCorners();
const corners2 = rect2.getCorners();

if (thisCorners[0].y <= otherCorners[0].y && thisCorners[2].y >= otherCorners[0].y) {
//The top edge of the other rectangle is within the horizontal boundaries
//of this rectangle
if (thisCorners[0].x <= otherCorners[0].x && thisCorners[1].x >= otherCorners[0].x) {
//The left edge of the other rectangle is within the vertical boundaries
//of this rectangle
return true;
} else if (
//The left edge of this rectangle is within the vertical boundaries
//of the other rectangle
otherCorners[0].x <= thisCorners[0].x &&
otherCorners[1].x >= thisCorners[0].x
) {
return true;
} else if (
//The right edge of the other rectangle is within the vertical boundaries
//of this rectangle
thisCorners[0].x <= otherCorners[1].x &&
thisCorners[1].x >= otherCorners[1].x
) {
return true;
} else if (
//The right edge of this rectangle is within the vertical boundaries
//of the other rectangle
otherCorners[0].x <= thisCorners[1].x &&
otherCorners[1].x >= thisCorners[1].x
) {
return true;
}

return false;
} else if (otherCorners[0].y <= thisCorners[0].y && otherCorners[2].y >= thisCorners[0].y) {
//The top edge of this rectangle is within the horizontal boundaries
//of the other rectangle
if (thisCorners[0].x <= otherCorners[0].x && thisCorners[1].x >= otherCorners[0].x) {
//The left edge of the other rectangle is within the vertical boundaries
//of this rectangle
return true;
} else if (
//The left edge of this rectangle is within the vertical boundaries
//of the other rectangle
otherCorners[0].x <= thisCorners[0].x &&
otherCorners[1].x >= thisCorners[0].x
) {
return true;
} else if (
//The right edge of the other rectangle is within the vertical boundaries
//of this rectangle
thisCorners[0].x <= otherCorners[1].x &&
thisCorners[1].x >= otherCorners[1].x
) {
return true;
} else if (
//The right edge of this rectangle is within the vertical boundaries
//of the other rectangle
otherCorners[0].x <= thisCorners[1].x &&
otherCorners[1].x >= thisCorners[1].x
) {
return true;
}

return false;
} else if (thisCorners[0].y <= otherCorners[2].y && thisCorners[2].y >= otherCorners[2].y) {
//The bottom edge of the other rectangle is within the horizontal boundaries
//of this rectangle
if (thisCorners[0].x <= otherCorners[0].x && thisCorners[1].x >= otherCorners[0].x) {
//The left edge of the other rectangle is within the vertical boundaries
//of this rectangle
return true;
} else if (
//The left edge of this rectangle is within the vertical boundaries
//of the other rectangle
otherCorners[0].x <= thisCorners[0].x &&
otherCorners[1].x >= thisCorners[0].x
) {
return true;
} else if (
//The right edge of the other rectangle is within the vertical boundaries
//of this rectangle
thisCorners[0].x <= otherCorners[1].x &&
thisCorners[1].x >= otherCorners[1].x
) {
return true;
} else if (
//The right edge of this rectangle is within the vertical boundaries
//of the other rectangle
otherCorners[0].x <= thisCorners[1].x &&
otherCorners[1].x >= thisCorners[1].x
) {
return true;
}

return false;
} else if (otherCorners[0].y <= thisCorners[2].y && otherCorners[2].y >= thisCorners[2].y) {
//The bottom edge of this rectangle is within the horizontal boundaries
//of the other rectangle
if (thisCorners[0].x <= otherCorners[0].x && thisCorners[1].x >= otherCorners[0].x) {
//The left edge of the other rectangle is within the vertical boundaries
//of this rectangle
return true;
} else if (
//The left edge of this rectangle is within the vertical boundaries
//of the other rectangle
otherCorners[0].x <= thisCorners[0].x &&
otherCorners[1].x >= thisCorners[0].x
) {
return true;
} else if (
//The right edge of the other rectangle is within the vertical boundaries
//of this rectangle
thisCorners[0].x <= otherCorners[1].x &&
thisCorners[1].x >= otherCorners[1].x
) {
return true;
} else if (
//The right edge of this rectangle is within the vertical boundaries
//of the other rectangle
otherCorners[0].x <= thisCorners[1].x &&
otherCorners[1].x >= thisCorners[1].x
) {
return true;
}

return false;
}

return false;
return (
//Check if the horizontal edges are within
((corners1[0].y <= corners2[0].y && corners1[2].y >= corners2[0].y) ||
(corners1[0].y <= corners2[2].y && corners1[2].y >= corners2[2].y)) &&
//Check if the vertical edges are within
((corners1[0].x <= corners2[0].x && corners1[1].x >= corners2[0].x) ||
(corners1[0].x <= corners2[1].x && corners1[1].x >= corners2[1].x))
);
}

/**
Expand All @@ -286,7 +163,7 @@ export function pointInRect(rect: Rectangle, point: Point): boolean {
* @param otherPoint The point that might be inside the given ellipse.
* @returns True, if the point is inside the given ellipse. Else, false
*/
export function pointInELlipse(ellipse: Ellipse, point: Point): boolean {
export function pointInEllipse(ellipse: Ellipse, point: Point): boolean {
//(x-h)^2/rx^2 + (y-k)^2/ry^2 <= 1
//(x, y) = new point
//(h, k) = center
Expand All @@ -296,7 +173,7 @@ export function pointInELlipse(ellipse: Ellipse, point: Point): boolean {
Math.pow(point.y - ellipse.center.y, 2) / Math.pow(ellipse.radiusY, 2);
//);

return p < 1;
return p <= 1;
}

/**
Expand Down Expand Up @@ -324,7 +201,8 @@ function getWidestCoordinates(ellipse: Ellipse): Point[] {
* @param ellipse The given ellipse
* @returns An array of points along the bounding curve of the ellipse
*/
function getEllipsePoints(ellipse: Ellipse, amount: number): Point[] {
export function getEllipsePoints(ellipse: Ellipse): Point[] {
const amount = 400;
const points: Point[] = [];
const pointDist = ellipse.radiusX / (amount / 4);

Expand All @@ -333,7 +211,7 @@ function getEllipsePoints(ellipse: Ellipse, amount: number): Point[] {
let y: number;

for (let i = 1; i < amount; i++) {
if (i < amount / 2 + 1) {
if (i <= amount / 2) {
x = points[i - 1].x + pointDist;
y = getCurvePoint(ellipse, x, 1);
} else {
Expand Down
Loading

0 comments on commit 70a3433

Please sign in to comment.