public XMLEntity getXMLEntity() {
    XMLEntity xml = new XMLEntity();
    xml.putProperty("className", getClassName());
    xml.putProperty("isShapeVisible", isShapeVisible());
    // color (necessite)
    if (getFillColor() != null)
      xml.putProperty("color", StringUtilities.color2String(getFillColor()));
    xml.putProperty("desc", getDescription());
    xml.putProperty("referenceSystem", getReferenceSystem());
    xml.putProperty("unit", getUnit());
    xml.addChild(markerSymbol.getXMLEntity());
    xml.addChild(markerFillProperties.getXMLEntity());

    if (getOutline() != null) {
      XMLEntity outlineXML = getOutline().getXMLEntity();
      outlineXML.putProperty("id", "outline symbol");
      xml.addChild(outlineXML);
    }
    xml.putProperty("hasOutline", hasOutline());
    return xml;
  }
  public void drawInsideRectangle(
      Graphics2D g, AffineTransform scaleInstance, Rectangle r, PrintRequestAttributeSet properties)
      throws SymbolDrawingException {
    markerFillProperties.setSampleSymbol(markerSymbol);
    switch (markerFillProperties.getFillStyle()) {
      case SINGLE_CENTERED_SYMBOL:
        FPoint2D p = new FPoint2D(r.getCenterX(), r.getCenterY());
        markerSymbol.draw(g, null, p, null);
        break;
      case GRID_FILL:
        {
          g.setClip(r);
          int size = (int) markerSymbol.getSize();
          if (size <= 0) size = 1;
          Rectangle rProv = new Rectangle();
          rProv.setFrame(0, 0, size, size);
          Paint resulPatternFill = null;

          BufferedImage sample = null;
          sample = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
          Graphics2D gAux = sample.createGraphics();

          double xSeparation = markerFillProperties.getXSeparation(); // TODO
          // apply
          // CartographicSupport
          double ySeparation = markerFillProperties.getYSeparation(); // TODO
          // apply
          // CartographicSupport
          double xOffset = markerFillProperties.getXOffset();
          double yOffset = markerFillProperties.getYOffset();

          markerSymbol.drawInsideRectangle(gAux, new AffineTransform(), rProv, properties);

          rProv.setRect(0, 0, rProv.getWidth() + xSeparation, rProv.getHeight() + ySeparation);

          BufferedImage bi =
              new BufferedImage(rProv.width, rProv.height, BufferedImage.TYPE_INT_ARGB);
          gAux = bi.createGraphics();
          gAux.drawImage(sample, null, (int) (xSeparation * 0.5), (int) (ySeparation * 0.5));

          resulPatternFill = new TexturePaint(bi, rProv);
          g.setColor(null);
          g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

          // g.translate(xOffset, rProv.getHeight()-yOffset);
          g.translate(xOffset, -yOffset);
          g.setPaint(resulPatternFill);
          g.fill(r);
          // g.translate(-xOffset, -rProv.getHeight()+yOffset);
          g.translate(-xOffset, yOffset);
          g.setClip(null);
        }
        break;
      case RANDOM_FILL:
        g.setClip(r);
        int x = r.x;
        int y = r.y;
        int width = r.width;
        int height = r.height;
        g.setBackground(null);

        markerSymbol.draw(g, null, new FPoint2D((x + width * 0.2), (y + height * 0.8)), null);
        markerSymbol.draw(g, null, new FPoint2D((x + width * 0.634), (y + height * 0.3)), null);
        markerSymbol.draw(g, null, new FPoint2D((x + width * 0.26), (y + height * 0.35)), null);
        markerSymbol.draw(g, null, new FPoint2D((x + width * 0.45), (y + height * 0.98)), null);
        markerSymbol.draw(g, null, new FPoint2D((x + width * 0.9), (y + height * 0.54)), null);
        markerSymbol.draw(g, null, new FPoint2D((x + width * 1.1), (y + height * 0.7)), null);
        g.setClip(null);
        break;
    }
    if (getOutline() != null && hasOutline()) {
      if (properties == null)
        getOutline().draw(g, scaleInstance, new FPolyline2D(new GeneralPathX(r)), null);
      else getOutline().print(g, scaleInstance, new FPolyline2D(new GeneralPathX(r)), properties);
    }
  }
  public void draw(Graphics2D g, AffineTransform affineTransform, FShape shp, Cancellable cancel) {
    switch (markerFillProperties.getFillStyle()) {
      case SINGLE_CENTERED_SYMBOL:
        // case a single marker is used into a polygon shapetype
        Geometry geom = FConverter.java2d_to_jts(shp);
        com.vividsolutions.jts.geom.Point centroid = geom.getCentroid();
        /*
         * Hay ocasiones en que jts no puede calcular un centroide y
         * devuelve NaN (por ejemplo con geometrías poligonales cuyos puntos
         * tienen todos la misma abscisa y distinta ordenada con tan solo
         * una diferencia de 1 ó 2 unidades) entonces, en lugar de utilizar
         * este centroide tomamos el centro del bounds del shp (la geometría
         * es tan pequeña que consideramos que deben coincidir).
         */
        if (!(Double.isNaN(centroid.getX()) || Double.isNaN(centroid.getY()))) {
          double centroidX = centroid.getX() + markerFillProperties.getXOffset();
          double centroidY = centroid.getY() + markerFillProperties.getYOffset();
          FPoint2D p = new FPoint2D(new Point2D.Double(centroidX, centroidY));
          markerSymbol.draw(g, affineTransform, p, null);
        } else {
          double centroidX = shp.getBounds().getCenterX();
          double centroidY = shp.getBounds().getCenterY();
          FPoint2D p = new FPoint2D(new Point2D.Double(centroidX, centroidY));
          markerSymbol.draw(g, affineTransform, p, null);
        }
        break;
      case GRID_FILL:
        // case a grid fill is used
        {
          Rectangle rClip = null;
          if (g.getClipBounds() != null) {
            rClip = (Rectangle) g.getClipBounds().clone();
            g.setClip(rClip.x, rClip.y, rClip.width, rClip.height);
          }
          g.clip(shp);

          int size = (int) markerSymbol.getSize();
          Rectangle rProv = new Rectangle();
          rProv.setFrame(0, 0, size, size);
          Paint resulPatternFill = null;

          double xSeparation = markerFillProperties.getXSeparation(); // TODO
          // apply
          // CartographicSupport
          double ySeparation = markerFillProperties.getYSeparation(); // TODO
          // apply
          // CartographicSupport
          double xOffset = markerFillProperties.getXOffset();
          double yOffset = markerFillProperties.getYOffset();

          BufferedImage sample = null;
          sample = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
          Graphics2D gAux = sample.createGraphics();

          try {
            markerSymbol.drawInsideRectangle(gAux, gAux.getTransform(), rProv, null);
          } catch (SymbolDrawingException e) {
            if (e.getType() == SymbolDrawingException.UNSUPPORTED_SET_OF_SETTINGS) {
              try {
                SymbologyFactory.getWarningSymbol(
                        SymbolDrawingException.STR_UNSUPPORTED_SET_OF_SETTINGS,
                        "",
                        SymbolDrawingException.UNSUPPORTED_SET_OF_SETTINGS)
                    .drawInsideRectangle(gAux, gAux.getTransform(), rProv, null);
              } catch (SymbolDrawingException e1) {
                // IMPOSSIBLE TO REACH THIS
              }
            } else {
              // should be unreachable code
              throw new Error(Messages.getString("symbol_shapetype_mismatch"));
            }
          }
          rProv.setRect(0, 0, rProv.getWidth() + xSeparation, rProv.getHeight() + ySeparation);

          BufferedImage bi =
              new BufferedImage(rProv.width, rProv.height, BufferedImage.TYPE_INT_ARGB);
          gAux = bi.createGraphics();
          gAux.drawImage(sample, null, (int) (xSeparation * 0.5), (int) (ySeparation * 0.5));

          resulPatternFill = new TexturePaint(bi, rProv);
          sample = null;
          gAux.dispose();

          g.setColor(null);
          g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

          g.translate(xOffset, -yOffset);
          g.setPaint(resulPatternFill);
          g.fill(shp);
          g.translate(-xOffset, +yOffset);
          g.setClip(rClip);
          bi = null;
        }
        break;
      case RANDOM_FILL:
        {
          double s = markerSymbol.getSize();
          Rectangle r = shp.getBounds();
          int drawCount = (int) (Math.min(r.getWidth(), r.getHeight()) / s);
          Random random = new Random();

          int minx = r.x;
          int miny = r.y;
          int width = r.width;
          int height = r.height;

          r = new Rectangle();
          g.setClip(shp);

          for (int i = 0; (cancel == null || !cancel.isCanceled()) && i < drawCount; i++) {
            int x = (int) Math.abs(random.nextDouble() * width);
            int y = (int) Math.abs(random.nextDouble() * height);
            x = x + minx;
            y = y + miny;
            markerSymbol.draw(g, new AffineTransform(), new FPoint2D(x, y), cancel);
          }
          g.setClip(null);
        }
        break;
    }
    if (getOutline() != null) {
      getOutline().draw(g, affineTransform, shp, cancel);
    }
  }