src/app/components/line-segment-component/models/line-segment-model.js
/*
* 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 { IntersectionModel } from "../../intersection-component/models/intersection-model";
import { ELEMENTS_CLASS } from "../../../core/enums/elements-class-enum";
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];
}
// 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.getIntersectionWithCircumference(geometricObject);
default:
break;
}
}
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)];
}
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)];
}
}
// Intersection with circunference
getIntersectionWithCircumference(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 cx = center.posX - pointA.posX;
const cy = center.posY - pointA.posY;
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; // (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 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) { //TODO Verificar? No intersection points
//D console.log("line-segment-model.js: getIntersectionWithCircumference(.): 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;
if (delta == 0) { //TODO Verificar? Only one point (actually, both with the same coordinates)
//D console.log("line-segment-model.js: getIntersectionWithCircumference(.): delta==0");
PA.bind(x1, y1, undefined, this, circumference, true, 0);
return [PA, PB];
}
if (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;
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];
} // getIntersectionWithCircumference(circumference)
// 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;
// comparacao cv do ponto A > cv da intersec => vazio
const cRA = dirX * this.pointA.posX + dirY * this.pointA.posY;
if (cInterA < cRA) { // d'P < d'A
return false;
}
// comparacao cv do ponto B < cv da intersec => vazio
const cRB = dirX * this.pointB.posX + dirY * this.pointB.posY;
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);
}
}