Class EllipticalCurveTo

java.lang.Object
com.itextpdf.svg.renderers.path.impl.AbstractPathShape
com.itextpdf.svg.renderers.path.impl.EllipticalCurveTo
All Implemented Interfaces:
IPathShape

public class EllipticalCurveTo extends AbstractPathShape
Implements elliptical curveTo (A) segment of SVG's path element. Implemented in PDF as Bézier curves. Edge cases & value correction below always refer to https://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes For some calculations we need double precision floating point math, so we have forced all calculations to use double. However, float comparison is used instead of double comparison, because close coordinates can be considered equal.
  • Field Details

  • Constructor Details

    • EllipticalCurveTo

      public EllipticalCurveTo()
      Creates an absolute Elliptical curveTo.
    • EllipticalCurveTo

      public EllipticalCurveTo(boolean relative)
      Creates a Elliptical curveTo. Set argument to true to create a relative EllipticalCurveTo.
      Parameters:
      relative - whether this is a relative EllipticalCurveTo or not
  • Method Details

    • setCoordinates

      public void setCoordinates(String[] inputCoordinates, Point previous)
      Description copied from interface: IPathShape
      This method sets the coordinates for the path painting operator and does internal preprocessing, if necessary
      Parameters:
      inputCoordinates - an array containing point values for path coordinates
      previous - the ending point of the previous operator, or, in broader terms, the point that the coordinates should be absolutized against, for relative operators
    • draw

      public void draw(PdfCanvas canvas)
      Description copied from interface: IPathShape
      Draws this instruction to a canvas object.
      Parameters:
      canvas - to which this instruction is drawn
    • rotate

      static Point[][] rotate(Point[][] list, double rotation, Point rotator)
      This convenience method rotates a given set of points around a given point
      Parameters:
      list - the input list
      rotation - the rotation angle, in radians
      rotator - the point to rotate around
      Returns:
      the list of rotated points
    • getCoordinates

      String[] getCoordinates()
    • drawCurve

      private static void drawCurve(PdfCanvas canvas, Point cp1, Point cp2, Point end)
    • makePoints

      private Point[][] makePoints(List<double[]> input)
    • getPathShapeRectangle

      public Rectangle getPathShapeRectangle(Point lastPoint)
      Description copied from class: AbstractPathShape
      Get bounding rectangle of the current path shape.
      Specified by:
      getPathShapeRectangle in interface IPathShape
      Overrides:
      getPathShapeRectangle in class AbstractPathShape
      Parameters:
      lastPoint - start point for this shape
      Returns:
      calculated rectangle
    • getCoordinate

      private double getCoordinate(int index)
    • getEllipticalArcMinMaxPoints

      private double[] getEllipticalArcMinMaxPoints(double x1, double y1, double rx, double ry, double phi, boolean largeArc, boolean sweep, double x2, double y2)
      Algorithm to find elliptical arc bounding box: 1. Compute extremes using parametric description of the whole ellipse We use parametric description of ellipse: x(theta) = cx + rx*cos(theta)*cos(phi) - ry*sin(theta)*sin(phi) y(theta) = cy + rx*cos(theta)*sin(phi) + ry*sin(theta)*cos(phi) After obtaining the derivative and equating it to zero, we get two solutions for x: theta = -atan(ry*tan(phi)/rx) and theta = M_PI -atan(ry*tan(phi)/rx) and two solutions for y: theta = atan(ry/(tan(phi)*rx)) and theta = M_PI + atan(ry/(tan(phi)*rx)) Then to get theta values we need to know cx and cy - the coordinates of the center of the ellipse. 2. Compute the center of the ellipse Method getEllipseCenterCoordinates(double, double, double, double, double, boolean, boolean, double, double) 3. Determine the bounding box of the whole ellipse When we know cx and cy values we can get the bounding box of whole ellipse. That done in the method getEllipseCenterCoordinates(double, double, double, double, double, boolean, boolean, double, double). 4. Find tightest possible bounding box Check that given points is on the arc using polar coordinates of points. Method isPointOnTheArc(double, double, double, boolean).
      Parameters:
      x1 - x coordinate of the starting point
      y1 - y coordinate of the starting point
      rx - x radius
      ry - y radius
      phi - x-axis rotation
      largeArc - large arc flag. If this is true, then one of the two larger arc sweeps will be chosen (greater than or equal to 180 degrees)
      sweep - sweep flag. If sweep flag is true, then the arc will be drawn in a "positive-angle" direction and if false - in a "negative-angle" direction
      x2 - x coordinate of ending point
      y2 - y coordinate of ending point
      Returns:
      array of {xMin, yMin, xMax, yMax} values
    • getEllipseCenterCoordinates

      private double[] getEllipseCenterCoordinates(double x1, double y1, double rx, double ry, double phi, boolean largeArc, boolean sweep, double x2, double y2)
      Calculate the center coordinates of the whole ellipse. Also return rx, ry values since they can be changed in this method. Algorithm for calculation centre coordinates: https://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
      Parameters:
      x1 - x coordinate of the starting point
      y1 - y coordinate of the starting point
      rx - x radius
      ry - y radius
      phi - x-axis rotation
      largeArc - large arc flag
      sweep - sweep flag
      x2 - x coordinate of ending point
      y2 - y coordinate of ending point
      Returns:
      the array of {cx, cy, rx, ry} values
    • getExtremeCoordinatesAndAngles

      private double[][] getExtremeCoordinatesAndAngles(double rx, double ry, double phi, double cx, double cy)
      Calculate extremes of the ellipse function and corresponding angles. Angles are calculated relative to the center of the ellipse.
      Parameters:
      rx - x radius
      ry - y radius
      phi - x-axis rotation
      cx - x coordinate of ellipse center
      cy - y coordinate of ellipse center
      Returns:
      array of extreme coordinate and array of angles corresponding to these coordinates.
    • isPointOnTheArc

      private boolean isPointOnTheArc(double pointAngle, double angle1, double angle2, boolean otherArc)
      Check that angle corresponding to extreme points is on the current arc. For this we check that this angle is between the angles of starting and ending points.
      Parameters:
      pointAngle - angle to check
      angle1 - angle of the first extreme point if ellipse(starting or ending)
      angle2 - angle of the second extreme point if ellipse(starting or ending)
      otherArc - if we should check that point is placed on the other arc of the current ellipse
      Returns:
      true if point is on the arc
    • getAngleBetweenVectors

      private double getAngleBetweenVectors(double bx, double by)
      Return the angle between the vector (1, 0) and the line specified by points (0, 0) and (bx, by) in range [ 0, Pi/2 ] U [ 3*Pi/2, 2*Pi). As the angle between vectors should cover the whole circle, i.e. [0, 2* Pi). General formula to find angle between two vectors is formula F.6.5.4 on the https://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter.
      Parameters:
      bx - x coordinate of the vector ending point
      by - y coordinate of the vector ending point
      Returns:
      calculated angle between vectors
    • anglesAreEquals

      private boolean anglesAreEquals(double angle1, double angle2)