getSelectionPoints()

in packages/ketcher-core/src/application/render/renderers/BondRenderer.ts [244:376]


  getSelectionPoints() {
    // please refer to: ketcher-core/docs/data/hover_selection_1.png
    const editor = CoreEditor.provideEditorInstance();
    const viewModel = editor.viewModel;
    const halfEdges = viewModel.bondsToHalfEdges.get(this.bond);
    const firstHalfEdge = halfEdges?.[0];
    const secondHalfEdge = halfEdges?.[1];
    const bond: Bond = this.bond;
    const bondSpacingInPx = 6;
    const stereoBondWidth = 6;
    const regularSelectionThikness = bondSpacingInPx + BOND_WIDTH;

    if (!firstHalfEdge || !secondHalfEdge) {
      KetcherLogger.warn(
        'Failed to draw selection for bond. There is no no half edges.',
      );

      return [];
    }

    // get half-bond positions, this is where the actual bond
    // image on the screen is drawn, it may be different e.g. if the
    // bond is connected to an atom with a label as opposed
    // to when it is connected to a Carbon atom w/o a label
    // please refer to: ketcher-core/docs/data/hover_selection_2.png
    let halfEdgeStart = Coordinates.modelToCanvas(firstHalfEdge.position);
    let halfEdgeEnd = Coordinates.modelToCanvas(secondHalfEdge.position);

    halfEdgeStart = this.shiftPositionIfAtomLabelVisible(
      halfEdgeStart,
      this.bond.firstAtom,
      firstHalfEdge,
    );

    halfEdgeEnd = this.shiftPositionIfAtomLabelVisible(
      halfEdgeEnd,
      this.bond.secondAtom,
      secondHalfEdge,
    );

    const isStereoBond = bond.stereo !== 0 && bond.stereo !== 3;

    const addPadding = isStereoBond ? 0 : -2;

    // find the points on the line where we will be drawing the curves
    const contourStart = Vec2.getLinePoint(
      halfEdgeEnd,
      halfEdgeStart,
      addPadding,
    );
    const contourEnd = Vec2.getLinePoint(
      halfEdgeStart,
      halfEdgeEnd,
      addPadding,
    );

    const stereoBondStartHeightCoef = 0.5;
    const bondPadding = 0.5;
    const addStart = isStereoBond
      ? stereoBondWidth * stereoBondStartHeightCoef
      : regularSelectionThikness + bondPadding;
    const stereoBondEndHeightCoef = 1;
    const addEnd = isStereoBond
      ? stereoBondWidth +
        (regularSelectionThikness * stereoBondEndHeightCoef) / stereoBondWidth
      : regularSelectionThikness + bondPadding;

    const contourPaddedStart = Vec2.getLinePoint(
      contourStart,
      contourEnd,
      addEnd,
    );
    const contourPaddedEnd = Vec2.getLinePoint(
      contourEnd,
      contourStart,
      addStart,
    );

    // we need four points for each bezier curve
    // and two for each line that together form the selection contour
    // the padded values are for the curve points and the rest of
    // the values are for drawing the lines
    // please refer to: ketcher-core/docs/data/hover_selection_3.png
    const startPoint = contourStart.add(new Vec2(addEnd, 0));
    const endPoint = contourEnd.add(new Vec2(addStart, 0));
    const padStartPoint = contourPaddedStart.add(new Vec2(addEnd, 0));
    const padEndPoint = contourPaddedEnd.add(new Vec2(addStart, 0));

    const angle =
      (Math.atan2(firstHalfEdge.direction.y, firstHalfEdge.direction.x) * 180) /
      Math.PI;

    // rotate the points +/-90 degrees to find the
    // perpendicular points that will be used for actual drawing
    // of selection contour on canvas
    const startTop = startPoint.rotateAroundOrigin(
      angle + 90,
      new Vec2(contourStart.x, contourStart.y),
    );
    const startBottom = startPoint.rotateAroundOrigin(
      angle - 90,
      new Vec2(contourStart.x, contourStart.y),
    );
    const startPadTop = padStartPoint.rotateAroundOrigin(
      angle + 90,
      contourPaddedStart,
    );
    const startPadBottom = padStartPoint.rotateAroundOrigin(
      angle - 90,
      contourPaddedStart,
    );
    const endTop = endPoint.rotateAroundOrigin(angle + 90, contourEnd);
    const endBottom = endPoint.rotateAroundOrigin(angle - 90, contourEnd);
    const endPadTop = padEndPoint.rotateAroundOrigin(
      angle + 90,
      contourPaddedEnd,
    );
    const endPadBottom = padEndPoint.rotateAroundOrigin(
      angle - 90,
      contourPaddedEnd,
    );

    return [
      startPadTop,
      startTop,
      endTop,
      endPadTop,
      endPadBottom,
      endBottom,
      startPadBottom,
      startBottom,
    ];
  }