public static Element drawCosine(SVGPlot svgp, Projection2D proj, NumberVector mid, double angle) {
    // Project origin
    double[] pointOfOrigin = proj.fastProjectDataToRenderSpace(new double[proj.getInputDimensionality()]);

    // direction of the selected Point
    double[] selPoint = proj.fastProjectDataToRenderSpace(mid);

    double[] range1, range2;
    {
      // Rotation plane:
      double[] pm = mid.toArray();
      // Compute relative vectors
      double[] p1 = minusEquals(proj.fastProjectRenderToDataSpace(selPoint[0] + 10, selPoint[1]), pm);
      double[] p2 = minusEquals(proj.fastProjectRenderToDataSpace(selPoint[0], selPoint[1] + 10), pm);
      // Scale p1 and p2 to unit length:
      timesEquals(p1, 1. / euclideanLength(p1));
      timesEquals(p2, 1. / euclideanLength(p2));
      if(Math.abs(scalarProduct(p1, p2)) > 1E-10) {
        LoggingUtil.warning("Projection does not seem to be orthogonal?");
      }
      // Project onto p1, p2:
      double l1 = scalarProduct(pm, p1), l2 = scalarProduct(pm, p2);
      // Rotate projection by + and - angle
      // Using sin(-x) = -sin(x) and cos(-x)=cos(x)
      final DoubleWrapper tmp = new DoubleWrapper(); // To return cosine
      final double sangle = FastMath.sinAndCos(angle, tmp), cangle = tmp.value;
      double r11 = +cangle * l1 - sangle * l2, r12 = +sangle * l1 + cangle * l2;
      double r21 = +cangle * l1 + sangle * l2, r22 = -sangle * l1 + cangle * l2;
      // Build rotated vectors - remove projected component, add rotated
      // component:
      double[] r1 = plusTimesEquals(plusTimes(pm, p1, -l1 + r11), p2, -l2 + r12);
      double[] r2 = plusTimesEquals(plusTimes(pm, p1, -l1 + r21), p2, -l2 + r22);
      // Project to render space:
      range1 = proj.fastProjectDataToRenderSpace(r1);
      range2 = proj.fastProjectDataToRenderSpace(r2);
    }

    // Continue lines to viewport.
    {
      CanvasSize viewport = proj.estimateViewport();
      minusEquals(range1, pointOfOrigin);
      plusEquals(timesEquals(range1, viewport.continueToMargin(pointOfOrigin, range1)), pointOfOrigin);
      minusEquals(range2, pointOfOrigin);
      plusEquals(timesEquals(range2, viewport.continueToMargin(pointOfOrigin, range2)), pointOfOrigin);
      // Go backwards into the other direction - the origin might not be in the
      // viewport!
      double[] start1 = minus(pointOfOrigin, range1);
      plusEquals(timesEquals(start1, viewport.continueToMargin(range1, start1)), range1);
      double[] start2 = minus(pointOfOrigin, range2);
      plusEquals(timesEquals(start2, viewport.continueToMargin(range2, start2)), range2);

      // TODO: add filled variant?
      return new SVGPath().moveTo(start1).lineTo(range1).moveTo(start2).lineTo(range2).makeElement(svgp);
    }
  }
public static Element drawCosine ( SVGPlot svgp , Projection2D proj , NumberVector mid , double angle ) { double [ ] pointOfOrigin = proj . fastProjectDataToRenderSpace ( new double [ proj . getInputDimensionality ( ) ] ) ; double [ ] selPoint = proj . fastProjectDataToRenderSpace ( mid ) ; double [ ] range1 , range2 ; { double [ ] pm = mid . toArray ( ) ; double [ ] p1 = minusEquals ( proj . fastProjectRenderToDataSpace ( selPoint [ 0 ] + 10 , selPoint [ 1 ] ) , pm ) ; double [ ] p2 = minusEquals ( proj . fastProjectRenderToDataSpace ( selPoint [ 0 ] , selPoint [ 1 ] + 10 ) , pm ) ; timesEquals ( p1 , 1. / euclideanLength ( p1 ) ) ; timesEquals ( p2 , 1. / euclideanLength ( p2 ) ) ; if ( Math . abs ( scalarProduct ( p1 , p2 ) ) > 1E-10 ) { LoggingUtil . warning ( "Projection does not seem to be orthogonal?" ) ; } double l1 = scalarProduct ( pm , p1 ) , l2 = scalarProduct ( pm , p2 ) ; final DoubleWrapper tmp = new DoubleWrapper ( ) ; final double sangle = FastMath . sinAndCos ( angle , tmp ) , cangle = tmp . value ; double r11 = + cangle * l1 - sangle * l2 , r12 = + sangle * l1 + cangle * l2 ; double r21 = + cangle * l1 + sangle * l2 , r22 = - sangle * l1 + cangle * l2 ; double [ ] r1 = plusTimesEquals ( plusTimes ( pm , p1 , - l1 + r11 ) , p2 , - l2 + r12 ) ; double [ ] r2 = plusTimesEquals ( plusTimes ( pm , p1 , - l1 + r21 ) , p2 , - l2 + r22 ) ; range1 = proj . fastProjectDataToRenderSpace ( r1 ) ; range2 = proj . fastProjectDataToRenderSpace ( r2 ) ; } { CanvasSize viewport = proj . estimateViewport ( ) ; minusEquals ( range1 , pointOfOrigin ) ; plusEquals ( timesEquals ( range1 , viewport . continueToMargin ( pointOfOrigin , range1 ) ) , pointOfOrigin ) ; minusEquals ( range2 , pointOfOrigin ) ; plusEquals ( timesEquals ( range2 , viewport . continueToMargin ( pointOfOrigin , range2 ) ) , pointOfOrigin ) ; double [ ] start1 = minus ( pointOfOrigin , range1 ) ; plusEquals ( timesEquals ( start1 , viewport . continueToMargin ( range1 , start1 ) ) , range1 ) ; double [ ] start2 = minus ( pointOfOrigin , range2 ) ; plusEquals ( timesEquals ( start2 , viewport . continueToMargin ( range2 , start2 ) ) , range2 ) ; return new SVGPath ( ) . moveTo ( start1 ) . lineTo ( range1 ) . moveTo ( start2 ) . lineTo ( range2 ) . makeElement ( svgp ) ; } }
Visualizes Cosine and ArcCosine distance functions

@param svgp SVG Plot
@param proj Visualization projection
@param mid mean vector
@param angle Opening angle in radians
@return path element