|
@@ -1,187 +1,200 @@
|
|
|
|
+/*
|
|
|
|
+ * iGeom by LInE
|
|
|
|
+ * Geometric Object: Segment
|
|
|
|
+ * Manage intersection of Segment with: Sements, Circumference
|
|
|
|
+ * www.matematica.br/igeom
|
|
|
|
+ * .app/components/line-segment-component/models/line-segment-model.js
|
|
|
|
+ * @version 2020/11/02: Implemented Line instersection
|
|
|
|
+ */
|
|
|
|
+
|
|
import { GeometricObject } from "../../../core/models/objects/geometric-object";
|
|
import { GeometricObject } from "../../../core/models/objects/geometric-object";
|
|
import { IntersectionModel } from "../../intersection-component/models/intersection-model";
|
|
import { IntersectionModel } from "../../intersection-component/models/intersection-model";
|
|
import { ELEMENTS_CLASS } from "../../../core/enums/elements-class-enum";
|
|
import { ELEMENTS_CLASS } from "../../../core/enums/elements-class-enum";
|
|
|
|
+
|
|
export class LineSegmentModel extends GeometricObject {
|
|
export class LineSegmentModel extends GeometricObject {
|
|
- constructor(pointA, pointB, label, id) {
|
|
|
|
- super(id);
|
|
|
|
- this.pointA = pointA;
|
|
|
|
- this.pointB = pointB;
|
|
|
|
- this.setLabel(label);
|
|
|
|
- super.setClass(ELEMENTS_CLASS.LINE_SEGMENT);
|
|
|
|
- this.definitions.push(this.pointA);
|
|
|
|
- this.definitions.push(this.pointB);
|
|
|
|
- }
|
|
|
|
- getStraight() {
|
|
|
|
- const aX = this.pointA.posX;
|
|
|
|
- const aY = this.pointA.posY;
|
|
|
|
- const bX = this.pointB.posX;
|
|
|
|
- const bY = this.pointB.posY;
|
|
|
|
- const a = bY - aY;
|
|
|
|
- const b = aX - bX;
|
|
|
|
- const c = a * aX + b * aY;
|
|
|
|
- return [a, b, c];
|
|
|
|
- }
|
|
|
|
- getDirection() {
|
|
|
|
- const aX = this.pointA.posX;
|
|
|
|
- const aY = this.pointA.posY;
|
|
|
|
- const bX = this.pointB.posX;
|
|
|
|
- const bY = this.pointB.posY;
|
|
|
|
- const a = bX - aX;
|
|
|
|
- const b = bY - aY;
|
|
|
|
- return [a, b];
|
|
|
|
- }
|
|
|
|
- getMiddlePoint() {
|
|
|
|
- const x = (this.pointA.posX + this.pointB.posX) / 2;
|
|
|
|
- const y = (this.pointA.posY + this.pointB.posY) / 2;
|
|
|
|
- return { posX: x, posY: y };
|
|
|
|
- }
|
|
|
|
- getIntersection(geometricObject) {
|
|
|
|
- switch (geometricObject.elementClass) {
|
|
|
|
- case ELEMENTS_CLASS.LINE_SEGMENT:
|
|
|
|
- return this.getIntersectionByLine(geometricObject);
|
|
|
|
- case ELEMENTS_CLASS.CIRCUMFERENCE:
|
|
|
|
- return this.getIntersectionByCircumference(geometricObject);
|
|
|
|
- default:
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ constructor(pointA, pointB, label, id) {
|
|
|
|
+ super(id);
|
|
|
|
+ this.pointA = pointA;
|
|
|
|
+ this.pointB = pointB;
|
|
|
|
+ this.setLabel(label);
|
|
|
|
+ super.setClass(ELEMENTS_CLASS.LINE_SEGMENT);
|
|
|
|
+ this.definitions.push(this.pointA);
|
|
|
|
+ this.definitions.push(this.pointB);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getStraight() {
|
|
|
|
+ const aX = this.pointA.posX;
|
|
|
|
+ const aY = this.pointA.posY;
|
|
|
|
+ const bX = this.pointB.posX;
|
|
|
|
+ const bY = this.pointB.posY;
|
|
|
|
+ const a = bY - aY;
|
|
|
|
+ const b = aX - bX;
|
|
|
|
+ const c = a * aX + b * aY;
|
|
|
|
+ return [a, b, c];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Return [(Bx-Ax, By-Ay)]
|
|
|
|
+ getDirection() {
|
|
|
|
+ const aX = this.pointA.posX;
|
|
|
|
+ const aY = this.pointA.posY;
|
|
|
|
+ const bX = this.pointB.posX;
|
|
|
|
+ const bY = this.pointB.posY;
|
|
|
|
+ const a = bX - aX;
|
|
|
|
+ const b = bY - aY;
|
|
|
|
+ return [a, b];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ getMiddlePoint() {
|
|
|
|
+ const x = (this.pointA.posX + this.pointB.posX) / 2;
|
|
|
|
+ const y = (this.pointA.posY + this.pointB.posY) / 2;
|
|
|
|
+ return { posX: x, posY: y };
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getIntersection(geometricObject) {
|
|
|
|
+ switch (geometricObject.elementClass) {
|
|
|
|
+ case ELEMENTS_CLASS.LINE: // StraightLine
|
|
|
|
+ return geometricObject.getIntersectionWithStraightLine(this); // Delegate to StraightLine
|
|
|
|
+ case ELEMENTS_CLASS.LINE_SEGMENT:
|
|
|
|
+ return this.getIntersectionByLine(geometricObject); //TODO nome deveria especificar SEGMENTO: this.getIntersectionWithSegment
|
|
|
|
+ case ELEMENTS_CLASS.CIRCUMFERENCE:
|
|
|
|
+ return this.getIntersectionByCircumference(geometricObject);
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
- getDeterminantByLine(lineSegment) {
|
|
|
|
- const r = this.getStraight();
|
|
|
|
- const s = lineSegment.getStraight();
|
|
|
|
- const a1 = r[0];
|
|
|
|
- const b1 = r[1];
|
|
|
|
- const a2 = s[0];
|
|
|
|
- const b2 = s[1];
|
|
|
|
- const determinant = a1 * b2 - a2 * b1;
|
|
|
|
- return determinant;
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getDeterminantByLine(lineSegment) {
|
|
|
|
+ const og1 = this.getStraight();
|
|
|
|
+ const og2 = lineSegment.getStraight();
|
|
|
|
+ const a1 = og1[0];
|
|
|
|
+ const b1 = og1[1];
|
|
|
|
+ const a2 = og2[0];
|
|
|
|
+ const b2 = og2[1];
|
|
|
|
+ const determinant = a1 * b2 - a2 * b1;
|
|
|
|
+ return determinant;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getIntersectionByLine(lineSegment) { //TODO nome deveria especificar SEGMENTO: getIntersectionWithSegment
|
|
|
|
+ const og1 = this.getStraight(); //r
|
|
|
|
+ const og2 = lineSegment.getStraight(); //s
|
|
|
|
+ const a1 = og1[0];
|
|
|
|
+ const b1 = og1[1];
|
|
|
|
+ const c1 = og1[2];
|
|
|
|
+ const a2 = og2[0];
|
|
|
|
+ const b2 = og2[1];
|
|
|
|
+ const c2 = og2[2];
|
|
|
|
+ const determinant = a1 * b2 - a2 * b1;
|
|
|
|
+ if (determinant == 0) {
|
|
|
|
+ return [new IntersectionModel(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, undefined, this, lineSegment, true, 0)];
|
|
}
|
|
}
|
|
- getIntersectionByLine(lineSegment) {
|
|
|
|
- const r = this.getStraight();
|
|
|
|
- const s = lineSegment.getStraight();
|
|
|
|
- const a1 = r[0];
|
|
|
|
- const b1 = r[1];
|
|
|
|
- const c1 = r[2];
|
|
|
|
- const a2 = s[0];
|
|
|
|
- const b2 = s[1];
|
|
|
|
- const c2 = s[2];
|
|
|
|
- const determinant = a1 * b2 - a2 * b1;
|
|
|
|
- if (determinant == 0) {
|
|
|
|
- return [
|
|
|
|
- new IntersectionModel(
|
|
|
|
- Number.MAX_SAFE_INTEGER,
|
|
|
|
- Number.MAX_SAFE_INTEGER,
|
|
|
|
- undefined,
|
|
|
|
- this,
|
|
|
|
- lineSegment,
|
|
|
|
- true,
|
|
|
|
- 0
|
|
|
|
- )
|
|
|
|
- ];
|
|
|
|
- } else {
|
|
|
|
- const x = (b2 * c1 - b1 * c2) / determinant;
|
|
|
|
- const y = (a1 * c2 - a2 * c1) / determinant;
|
|
|
|
- return [new IntersectionModel(x, y, undefined, this, lineSegment, true, 0)];
|
|
|
|
- }
|
|
|
|
|
|
+ else {
|
|
|
|
+ const x = (b2 * c1 - b1 * c2) / determinant;
|
|
|
|
+ const y = (a1 * c2 - a2 * c1) / determinant;
|
|
|
|
+ return [new IntersectionModel(x, y, undefined, this, lineSegment, true, 0)];
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- getIntersectionByCircumference(circumference) {
|
|
|
|
-
|
|
|
|
- const pointA = this.pointA;
|
|
|
|
- const pointB = this.pointB;
|
|
|
|
- const center = circumference.center;
|
|
|
|
- const radius = circumference.getRadius();
|
|
|
|
|
|
+ // Intersection with circunference
|
|
|
|
+ getIntersectionByCircumference(circumference) { //TODO Nome? Melhor 'getIntersectionWithCircumference'
|
|
|
|
+ const pointA = this.pointA;
|
|
|
|
+ const pointB = this.pointB;
|
|
|
|
+ const center = circumference.center;
|
|
|
|
+ const radius = circumference.getRadius();
|
|
|
|
|
|
- const dx = pointB.posX - pointA.posX;
|
|
|
|
- const dy = pointB.posY - pointA.posY;
|
|
|
|
|
|
+ const dx = pointB.posX - pointA.posX;
|
|
|
|
+ const dy = pointB.posY - pointA.posY;
|
|
|
|
|
|
- const cx = center.posX - pointA.posX;
|
|
|
|
- const cy = center.posY - pointA.posY;
|
|
|
|
|
|
+ const cx = center.posX - pointA.posX;
|
|
|
|
+ const cy = center.posY - pointA.posY;
|
|
|
|
|
|
- const a = dx * dx + dy * dy;
|
|
|
|
- const b = dx * cx + dy * cy;
|
|
|
|
- const c = cx * cx + cy * cy - radius * radius;
|
|
|
|
|
|
+ const a = dx * dx + dy * dy; // ||B-A||^2 = (B-A)'(B-A)
|
|
|
|
+ const b = dx * cx + dy * cy; // (B-A)'(C-A)
|
|
|
|
+ const c = cx * cx + cy * cy - radius * radius; // ||C-A||^2 - r^2
|
|
|
|
|
|
- const D = b / a;
|
|
|
|
- const q = c / a;
|
|
|
|
|
|
+ const D = b / a; // (B-A)'(C-A) / (B-A)'(B-A)
|
|
|
|
+ const q = c / a; // (||C-A||^2 - r^2) / (B-A)'(B-A)
|
|
|
|
|
|
- const delta = D * D - q;
|
|
|
|
|
|
+ const delta = D * D - q;
|
|
|
|
|
|
- const PA = new IntersectionModel(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, undefined, this, circumference, false, 0);
|
|
|
|
- const PB = new IntersectionModel(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, undefined, this, circumference, false, 1);
|
|
|
|
|
|
+ const PA = new IntersectionModel(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, undefined, this, circumference, false, 0);
|
|
|
|
+ const PB = new IntersectionModel(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, undefined, this, circumference, false, 1);
|
|
|
|
|
|
- if (delta < 0) {
|
|
|
|
- return [
|
|
|
|
- PA,
|
|
|
|
- PB
|
|
|
|
- ];
|
|
|
|
- }
|
|
|
|
|
|
+ if (delta < 0) { //TODO Verificar? No intersection points
|
|
|
|
+ //D console.log("line-segment-model.js: getIntersectionByCircumference(.): delta<0: " + Number.MAX_SAFE_INTEGER);
|
|
|
|
+ return [PA, PB];
|
|
|
|
+ }
|
|
|
|
|
|
- const deltaSqrt = Math.sqrt(delta);
|
|
|
|
- const root1 = -D + deltaSqrt;
|
|
|
|
- const root2 = -D - deltaSqrt;
|
|
|
|
- const x1 = pointA.posX - dx * root1
|
|
|
|
- const y1 = pointA.posY - dy * root1;
|
|
|
|
|
|
+ const deltaSqrt = Math.sqrt(delta);
|
|
|
|
+ const root1 = -D + deltaSqrt;
|
|
|
|
+ const root2 = -D - deltaSqrt;
|
|
|
|
+ const x1 = pointA.posX - dx * root1
|
|
|
|
+ const y1 = pointA.posY - dy * root1;
|
|
|
|
|
|
- if (delta == 0) {
|
|
|
|
- PA.bind(x1, y1, undefined, this, circumference, true, 0);
|
|
|
|
- return [
|
|
|
|
- PA,
|
|
|
|
- PB
|
|
|
|
- ];
|
|
|
|
- }
|
|
|
|
|
|
+ if (delta == 0) { //TODO Verificar? Only one point (actually, both with the same coordinates)
|
|
|
|
+ //D console.log("line-segment-model.js: getIntersectionByCircumference(.): delta==0");
|
|
|
|
+ PA.bind(x1, y1, undefined, this, circumference, true, 0);
|
|
|
|
+ return [PA, PB];
|
|
|
|
+ }
|
|
|
|
|
|
- const x2 = pointA.posX - dx * root2;
|
|
|
|
- const y2 = pointA.posY - dy * root2;
|
|
|
|
|
|
+ if (delta == 0) {
|
|
|
|
+ PA.bind(x1, y1, undefined, this, circumference, true, 0);
|
|
|
|
+ return [
|
|
|
|
+ PA,
|
|
|
|
+ PB
|
|
|
|
+ ];
|
|
|
|
+ }
|
|
|
|
|
|
- PA.bind(x1, y1, undefined, this, circumference, true, 0);
|
|
|
|
- PB.bind(x2, y2, undefined, this, circumference, true, 1);
|
|
|
|
|
|
+ const x2 = pointA.posX - dx * root2;
|
|
|
|
+ const y2 = pointA.posY - dy * root2;
|
|
|
|
|
|
- if (this.visible) {
|
|
|
|
- if (!this.insideSegment(PA.posX, PA.posY))
|
|
|
|
- PA.bind(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, undefined, this, circumference, false, 0)
|
|
|
|
|
|
+ PA.bind(x1, y1, undefined, this, circumference, true, 0);
|
|
|
|
+ PB.bind(x2, y2, undefined, this, circumference, true, 1);
|
|
|
|
|
|
- if (!this.insideSegment(PB.posX, PB.posY))
|
|
|
|
- PB.bind(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, undefined, this, circumference, false, 1);
|
|
|
|
- }
|
|
|
|
- return [
|
|
|
|
- PA,
|
|
|
|
- PB
|
|
|
|
- ];
|
|
|
|
|
|
+ if (!this.insideSegment(PB.posX, PB.posY))
|
|
|
|
+ PB.bind(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, undefined, this, circumference, false, 1);
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ return [PA, PB];
|
|
|
|
+ } // getIntersectionByCircumference(circumference)
|
|
|
|
|
|
- insideSegment(intersecX, intersecY) {
|
|
|
|
- const valuesR = this.getDirection();
|
|
|
|
- const dirX = valuesR[0];
|
|
|
|
- const dirY = valuesR[1];
|
|
|
|
- const cInterA = dirX * intersecX + dirY * intersecY;
|
|
|
|
|
|
|
|
- // comparaca cv do ponto A > cv da intersec => vazio
|
|
|
|
- const cRA = dirX * this.pointA.posX + dirY * this.pointA.posY;
|
|
|
|
|
|
+ // Considering de "level set" defined by direction d=B-A and intersection P,
|
|
|
|
+ // if d'P<d'A or d'P>d'B, then intersection is empty
|
|
|
|
+ insideSegment(intersecX, intersecY) {
|
|
|
|
+ //D console.log("line-segment-model.js: insideSegment(.)");
|
|
|
|
+ const valuesR = this.getDirection(); // get d=B-A
|
|
|
|
+ const dirX = valuesR[0]; // Bx-Ax
|
|
|
|
+ const dirY = valuesR[1]; // By-Ay
|
|
|
|
+ const cInterA = dirX * intersecX + dirY * intersecY;
|
|
|
|
|
|
- if (cInterA < cRA) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
|
|
+ // comparacao cv do ponto A > cv da intersec => vazio
|
|
|
|
+ const cRA = dirX * this.pointA.posX + dirY * this.pointA.posY;
|
|
|
|
|
|
- // comparaca cv do ponto B < cv da intersec => vazio
|
|
|
|
- const cRB = dirX * this.pointB.posX + dirY * this.pointB.posY;
|
|
|
|
|
|
+ if (cInterA < cRA) { // d'P < d'A
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
|
|
- if (cInterA > cRB) {
|
|
|
|
- this.posX = Number.MAX_SAFE_INTEGER;
|
|
|
|
- this.posY = Number.MAX_SAFE_INTEGER;
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
|
|
+ // comparacao cv do ponto B < cv da intersec => vazio
|
|
|
|
+ const cRB = dirX * this.pointB.posX + dirY * this.pointB.posY;
|
|
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- static do(map, list) {
|
|
|
|
- const id = map.get("id");
|
|
|
|
- const pointAId = map.get("param")[0];
|
|
|
|
- const pointBId = map.get("param")[1];
|
|
|
|
- const pointA = list.find(x => x.id === pointAId);
|
|
|
|
- const pointB = list.find(x => x.id === pointBId);
|
|
|
|
- const label = map.get("label")[0];
|
|
|
|
- return new LineSegmentModel(pointA, pointB, label, id);
|
|
|
|
|
|
+ if (cInterA > cRB) { // d'P > d'B
|
|
|
|
+ this.posX = Number.MAX_SAFE_INTEGER;
|
|
|
|
+ this.posY = Number.MAX_SAFE_INTEGER;
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static do(map, list) {
|
|
|
|
+ const id = map.get("id");
|
|
|
|
+ const pointAId = map.get("param")[0];
|
|
|
|
+ const pointBId = map.get("param")[1];
|
|
|
|
+ const pointA = list.find(x => x.id === pointAId);
|
|
|
|
+ const pointB = list.find(x => x.id === pointBId);
|
|
|
|
+ const label = map.get("label")[0];
|
|
|
|
+ return new LineSegmentModel(pointA, pointB, label, id);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|