Home Reference Source Repository

src/app/components/middle-point/models/middle-point-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 MiddlePointModel extends GeometricObject {

    constructor(pointA, pointB, pointC, label, id) {
        super(id);
        this.pointA = pointA;
        this.pointB = pointB;
        this.pointC = pointC;
        const middlePoint = this.getMiddlePoint();
        pointC.bind(middlePoint.posX, middlePoint.posY);
        this.setLabel(label);
        super.setClass(ELEMENTS_CLASS.MIDDLE_POINT);
        this.definitions.push(this.pointA);
        this.definitions.push(this.pointB);
        this.definitions.push(this.pointC);

    }

    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() {
        return MiddlePointModel.getMiddlePointPos(this.pointA, this.pointB);
    }

    static getMiddlePointPos(pointA, pointB) {
        const x = (pointA.posX + pointB.posX) / 2;
        const y = (pointA.posY + 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) {
        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 pointCId = map.get("param")[3];
        const pointA = list.find(x => x.id === pointAId);
        const pointB = list.find(x => x.id === pointBId);
        const pointC = list.find(x => x.id === pointCId);
        const label = map.get("label")[0];
        return new MiddlePointModel(pointA, pointB, pointC, label, id);
    }

}