/**
  * Transforms the figure.
  *
  * @param tx the transformation.
  */
 public void transform(AffineTransform tx) {
   if (TRANSFORM.get(this) != null
       || tx.getType() != (tx.getType() & AffineTransform.TYPE_TRANSLATION)) {
     if (TRANSFORM.get(this) == null) {
       TRANSFORM.basicSet(this, (AffineTransform) tx.clone());
     } else {
       AffineTransform t = TRANSFORM.getClone(this);
       t.preConcatenate(tx);
       TRANSFORM.basicSet(this, t);
     }
   } else {
     for (int i = 0; i < coordinates.length; i++) {
       tx.transform(coordinates[i], coordinates[i]);
     }
     if (FILL_GRADIENT.get(this) != null && !FILL_GRADIENT.get(this).isRelativeToFigureBounds()) {
       Gradient g = FILL_GRADIENT.getClone(this);
       g.transform(tx);
       FILL_GRADIENT.basicSet(this, g);
     }
     if (STROKE_GRADIENT.get(this) != null
         && !STROKE_GRADIENT.get(this).isRelativeToFigureBounds()) {
       Gradient g = STROKE_GRADIENT.getClone(this);
       g.transform(tx);
       STROKE_GRADIENT.basicSet(this, g);
     }
   }
   invalidate();
 }
 /** Checks if a Point2D.Double is inside the figure. */
 public boolean contains(Point2D.Double p) {
   if (TRANSFORM.get(this) != null) {
     try {
       p = (Point2D.Double) TRANSFORM.get(this).inverseTransform(p, new Point2D.Double());
     } catch (NoninvertibleTransformException ex) {
       ex.printStackTrace();
     }
   }
   return getTextShape().getBounds2D().contains(p);
 }
 @Override
 public Rectangle2D.Double getDrawingArea() {
   if (cachedDrawingArea == null) {
     Rectangle2D rx = getBounds();
     Rectangle2D.Double r =
         (rx instanceof Rectangle2D.Double)
             ? (Rectangle2D.Double) rx
             : new Rectangle2D.Double(rx.getX(), rx.getY(), rx.getWidth(), rx.getHeight());
     double g = SVGAttributeKeys.getPerpendicularHitGrowth(this);
     Geom.grow(r, g, g);
     if (TRANSFORM.get(this) == null) {
       cachedDrawingArea = r;
     } else {
       cachedDrawingArea = new Rectangle2D.Double();
       cachedDrawingArea.setRect(TRANSFORM.get(this).createTransformedShape(r).getBounds2D());
     }
   }
   return (Rectangle2D.Double) cachedDrawingArea.clone();
 }
 public void restoreTransformTo(Object geometry) {
   Object[] restoreData = (Object[]) geometry;
   TRANSFORM.basicSetClone(this, (AffineTransform) restoreData[0]);
   Point2D.Double[] restoredCoordinates = (Point2D.Double[]) restoreData[1];
   for (int i = 0; i < this.coordinates.length; i++) {
     coordinates[i] = (Point2D.Double) restoredCoordinates[i].clone();
   }
   FILL_GRADIENT.basicSetClone(this, (Gradient) restoreData[2]);
   STROKE_GRADIENT.basicSetClone(this, (Gradient) restoreData[3]);
   invalidate();
 }
 public Object getTransformRestoreData() {
   Point2D.Double[] restoredCoordinates = (Point2D.Double[]) this.coordinates.clone();
   for (int i = 0; i < this.coordinates.length; i++) {
     restoredCoordinates[i] = (Point2D.Double) this.coordinates[i].clone();
   }
   return new Object[] {
     TRANSFORM.getClone(this),
     restoredCoordinates,
     FILL_GRADIENT.getClone(this),
     STROKE_GRADIENT.getClone(this),
   };
 }
 public void setFontSize(float size) {
   // FONT_SIZE.basicSet(this, new Double(size));
   Point2D.Double p = new Point2D.Double(0, size);
   AffineTransform tx = TRANSFORM.get(this);
   if (tx != null) {
     try {
       tx.inverseTransform(p, p);
       Point2D.Double p0 = new Point2D.Double(0, 0);
       tx.inverseTransform(p0, p0);
       p.y -= p0.y;
     } catch (NoninvertibleTransformException ex) {
       ex.printStackTrace();
     }
   }
   FONT_SIZE.set(this, Math.abs(p.y));
 }
 public float getFontSize() {
   //   return FONT_SIZE.get(this).floatValue();
   Point2D.Double p = new Point2D.Double(0, FONT_SIZE.get(this));
   AffineTransform tx = TRANSFORM.get(this);
   if (tx != null) {
     tx.transform(p, p);
     Point2D.Double p0 = new Point2D.Double(0, 0);
     tx.transform(p0, p0);
     p.y -= p0.y;
     /*
     try {
         tx.inverseTransform(p, p);
     } catch (NoninvertibleTransformException ex) {
         ex.printStackTrace();
     }*/
   }
   return (float) Math.abs(p.y);
 }