Browse Source

Add 'src/app/components/line-component/drawers/line-drawer.js'

New package:
- ./app/components/line-component/models/line-model.js
- ./app/components/line-component/drawers/line-drawer.js
Implementation of intersection with StraightLine
leo 4 năm trước cách đây
mục cha
commit
4dd2c396a3
1 tập tin đã thay đổi với 227 bổ sung0 xóa
  1. 227 0
      src/app/components/line-component/drawers/line-drawer.js

+ 227 - 0
src/app/components/line-component/drawers/line-drawer.js

@@ -0,0 +1,227 @@
+/*
+ * iGeom by LInE
+ * Geometric Object: Straight Line
+ * www.matematica.br/igeom
+ * ./app/components/line-component/drawers/line-drawer.js
+ * Draw the Straight Line
+ */
+
+import { stageManager } from "../../../core/application/stage-manager"; // to get Canvas size 'stageManager.getSize();'
+
+import { ELEMENTS_CLASS } from "../../../core/enums/elements-class-enum";
+import { label as Label } from "../../../component-registry/label";
+import { LineModel } from "../models/line-model";
+import { objects as Objects } from "../../../core/application/objects";
+import { SelectableDrawer } from "../../../core/drawers/selectable-drawer";
+import { LineSegmentDrawer } from "../../line-segment-component/drawers/line-segment-drawer";
+import { DrawerAggregator } from "../../../core/drawers/drawer-aggregator";
+import { LineSegmentModel } from "../../line-segment-component/models/line-segment-model";
+
+export class LineDrawer extends LineSegmentDrawer {
+
+  constructor () {
+    super();
+    this.setElementClass(ELEMENTS_CLASS.LINE);
+    }
+
+  drawByStates (konvaObject) {
+    let aggregator = undefined;
+    if (konvaObject != undefined) {
+      aggregator = Objects.getByKonvaObject(konvaObject)[0];
+      }
+    if (this.state == undefined) {
+      super.setState(LineDrawer.FIRST_POINT_STATE);
+    } else if (this.state == LineDrawer.FIRST_POINT_STATE) {
+      aggregator = aggregator != undefined ? aggregator : this.pointDrawer.drawPoint();
+      this.setAggregatorA(aggregator);
+      super.setState(LineDrawer.SECOND_POINT_STATE);
+    } else if (this.state == LineDrawer.SECOND_POINT_STATE) {
+      aggregator = aggregator != undefined ? aggregator : this.pointDrawer.drawPoint();
+      this.setAggregatorB(aggregator);
+      this.drawByPoints([this.pointA, this.pointB], [this.aggregatorA, this.aggregatorB]);
+      super.setState(LineDrawer.FIRST_POINT_STATE);
+      }
+    }
+
+  drawByLineSegment (lineSegment) { //TODO Nome adequado? Nao seria 'drawLine(lineSegment)'?
+    this.lineSegment = lineSegment;
+    const group = SelectableDrawer.getKonvaGroup(false);
+    const text = LineDrawer.getKonvaText(lineSegment, lineSegment.label);
+    group.add(text);
+    const konvaObject = LineDrawer.getKonvaLine(lineSegment.pointA, lineSegment.pointB);
+    group.add(konvaObject);
+    super.setKonvaObject(group);
+    const aggregator = new DrawerAggregator(this, this.lineSegment, group, ELEMENTS_CLASS.LINE);
+    super.addAggregator(aggregator);
+    const aggregators = this.resolveAggregators([this.lineSegment.pointA, this.lineSegment.pointB], undefined);
+    aggregators[1].addAggregator(aggregator);
+    aggregators[0].addAggregator(aggregator);
+
+    // Sequence of calls:
+    // ./app/core/drawers/drawer.js: static drawObject(object): DrawerManager.draw(object);
+    // ./app/core/drawers/drawer-manager.js: draw(object): this.currentStage.draw(object);
+    SelectableDrawer.drawObject(this.konvaObject); // in ./app/core/drawers/drawer.js: static drawObject(object): DrawerManager.draw(object);
+
+    this.konvaObject.zIndex(1);
+    //leo super.batchDraw(); //D usar novo metodo para desenhar, aproveitar o proprio 'update' - REMOVER
+    this.update(aggregator,null);
+
+    SelectableDrawer.setMaxIndex(aggregators[0].konvaObject); // mark object 1: A
+    SelectableDrawer.setMaxIndex(aggregators[1].konvaObject); // mark object 2: B
+    }
+
+  // Draw Straight Line by its points
+  drawByPoints (points, aggregators) {
+    if (points == undefined || points.length < 1) return;
+    this.setPointA(points[0]);
+    this.setPointB(points[1]);
+    aggregators = this.resolveAggregators(points, aggregators, true);
+    this.label = Label.draw(true);
+    this.lineSegment = new LineModel(this.pointA, this.pointB, this.label);
+
+    // ./app/components/line-segment-component/drawers/line-segment-drawer.js
+    // Use: ./app/components/line-segment-component/drawers/line-segment-drawer.js: drawByLineSegment(lineSegment)
+    // Use: ./app/components/core/drawers/selectable-drawer
+    this.drawByLineSegment(this.lineSegment); // here, makes: SelectableDrawer.drawObject(this.konvaObject);
+    this.reset();
+    }
+
+
+  // Update straight line (Line)
+  // Whenever points A=(ax,ay) or B=(bx,by), was moved
+  // Let d=B-A, i.e., d=(dx,dy) where: dx=bx-ax, dy=by-ay
+  // If necessary semi-space: build the vector "o" (ortogonal to the segment AB), with
+  //    "o"=(ox,oy) with ox = -dy,  oy = dx    (then the scalar product "o" by d is: o'd = ox*dx+oy*dy = -dy*dx+dx*dy = -dy*dx+dy*dx = 0 CQD)
+  //
+  // Model under Canvas: r(.) parametric equation of the straight line
+  //
+  // Possible configurations to be considered:
+  //    +----------+----------+----------+----------+
+  //    | A x      |      x B | B x      |     x A  |
+  //    |     x B  |  A x     |     x A  | B x      |
+  //    |   (1)    |    (2)   |   (3)    |   (4)    |
+  //    +----------+----------+----------+----------+
+  // Straight line defined by points A,B (parametric equation by 'g'):
+  //   P(g) = A + g * (B-A) = A + g * d
+  
+  // Given W=canvas width and H=canvas height, find intersections with borders, i.e., find values of "g" such that:
+  //   r(g).x=0 or r(g).x=W or r(g).y=0 or r(g).y=H  (call this "g" respectively as Lg, Rg, Ug, and Dg - these are dependent of A and B positions)
+  //             Ug                 
+  // (0,0) +-------------+ (W,0)    Lg: 0 = r(g).x = A.x + g.x * d.x => g.x = -A.x / d.x
+  //       |             |          Rg: W = r(g).x = A.x + g.x * d.x => g.x = (W-A.x) / d.x
+  //   Lg  |             |  Rg
+  //       |             |          Ug: 0 = r(g).y = A.y + g.y * d.y => g.y = -A.y / d.y
+  // (0,H) +-------------+ (W,a)    Dg: H = r(g).y = A.y + g.y * d.y => g.y = (H-A.y) / d.y
+  //             Dg
+  //
+  // (1)                 Ug                             (2)           Dg
+  // (0,0) +------------o------------------+-->   (0,0) +------------o------------------+-->
+  //       |        o B  Q                 |            |        o A  Q                 |   
+  //    Lg |P    o A                       | Rg      Rg |     o B                       | Lg
+  //       +-o-----------------------------+            +-o-----------------------------+   
+  //      \|/            Dg                                           Ug  
+  update (aggregator, e) {
+    if (!aggregator.visible) return;
+    const pointA = aggregator.genericObject.pointA; // A
+    const pointB = aggregator.genericObject.pointB; // B
+    const Ax = pointA.posX, Ay = pointA.posY, Bx = pointB.posX, By = pointB.posY; // A=(Ax,Ay) and B=(Bx,By)
+    const dx = Bx-Ax, dy = By-Ay; // direction d=B-A
+    const size  = stageManager.getSize(); // From: ../../../core/application/stage-manager
+    const W = size.w; // canvas width
+    const H = size.h; // canvas height
+    var Ix, Iy, Ex, Ey; // Point I will be left-bottom one and E will be the top-right one
+    var Lg, Rg, Ug, Dg;
+    // Line perpendicular to axis "x" (dx = 0)
+    if (dx === 0) {
+      // Calculates parameters Ug, Dg:
+      Ug = -Ay / dy;    // -A.y / d.y
+      Dg = (H-Ay) / dy; // (H-A.y) / d.y
+      // Find the situation (1), (2), (3) or (4) calculating "ming" the smallest "g" and "maxg" the greatest "g"
+      const ming = Math.min(Ug, Dg); // minimum
+      const maxg = Math.max(Ug, Dg); // maximum
+      // Draw from minimum to maximum
+      Ix = Ax; Lg = 0;
+      Iy = Ay + ming * dy; // left initial point of this line (Ix, Iy)
+      Ex = Ax; Rg = 0;
+      Ey = Ay + maxg * dy; // right end    point of this line (Ex, Ey)
+      }
+    else {
+      // Calculates parameters Lg, Rg, Ug, Dg:
+      Lg = -Ax / dx;    // -A.x / d.x
+      Rg = (W-Ax) / dx; // (W-A.x) / d.x
+      Ug = -Ay / dy;    // -A.y / d.y
+      Dg = (H-Ay) / dy; // (H-A.y) / d.y
+      // Find the situation (1), (2), (3) or (4) calculating "ming" the smallest "g" and "maxg" the greatest "g"
+      var ming, maxg; // calculate extreme points (intercepted with the Canvas frame)
+      if (dx>0) { // (1)
+        if (Lg<Dg) ming = Dg;
+        else ming = Lg;
+        if (Rg>Ug) maxg = Ug;
+        else maxg = Rg;
+        }
+      else { // (2)
+        if (Lg>Ug) ming = Ug;
+        else ming = Lg;
+        if (Rg<Dg) maxg = Dg;
+        else maxg = Rg;
+        }
+      // Draw from minimum to maximum
+      Ix = Ax + ming * dx;
+      Iy = Ay + ming * dy; // left initial point of this line (Ix, Iy)
+      Ex = Ax + maxg * dx;
+      Ey = Ay + maxg * dy; // right end    point of this line (Ex, Ey)
+      }
+
+    // Ix = Ax; Iy = H; Ex = Ax; Ey = 0;
+    const points = [Ix, Iy, Ex, Ey];      
+    //D console.log("./app/components/line-component/drawers/line-drawer.js: update(aggregator, e):\nA=("+Ax+","+Ay+"), B=("+Bx+","+By+")"); //leo
+
+    // Update label line
+    const pos = aggregator.genericObject.getMiddlePoint();
+    aggregator.konvaObject.children[0].x(pos.posX);
+    aggregator.konvaObject.children[0].y(pos.posY - 20);
+
+    aggregator.konvaObject.children[1].points(points);
+
+    super.batchDraw();
+    } // update(aggregator, e)
+
+
+  static getKonvaLine (pointA, pointB, useLabel) { //TODO: revisar, pois o codigo 'slope', 'linearCoefficient' so' funciona para quadrantes 1 e 3...
+    const xA = pointA.posX, xB = pointB.posX,
+          yA = pointA.posY, yB = pointB.posY;
+
+    const slope = (yB - yA) / (xB - xA);
+    const linearCoefficient = (yA * xB - yB * xA) / (xB - xA);
+
+    const y = linearCoefficient;
+    const x = -linearCoefficient / slope;
+
+    const points = [x, 0, 0, y];
+
+    const line = new Konva.Line({
+      points: points,
+      stroke: "grey",
+      strokeWidth: 2,
+      lineJoin: "round",
+      draggable: false,
+      strokeScaleEnabled: false,
+      class: ELEMENTS_CLASS.LINE,
+      connections: [],
+      index: 1,
+      selectable: false,
+      draggable: false,
+      style: { stroke: "grey", fill: "grey" }
+    });
+
+    SelectableDrawer.setSelectableIfIntersectionChanged(line);
+
+    return line;
+    }
+
+  static drawKonvaLine (pointA, pointB) {
+    const line = LineDrawer.getKonvaLine(pointA, pointB);
+    return line;
+    }
+
+  }