Example #1
0
 public Point2D getCenterPoint() {
   if (centerPoint == null) {
     centerPoint =
         new Point2D.Double(
             area.getBounds().x + area.getBounds().width / 2,
             area.getBounds().y + area.getBounds().height / 2);
   }
   return centerPoint;
 }
Example #2
0
  /**
   * Like copyFrom, but will only copy the area specified.
   *
   * @see TileLayer#copyFrom(MapLayer)
   * @param other
   * @param mask
   */
  @Override
  public void maskedCopyFrom(MapLayer other, Area mask) {
    Rectangle boundBox = mask.getBounds();

    for (int y = boundBox.y; y < boundBox.y + boundBox.height; y++) {
      for (int x = boundBox.x; x < boundBox.x + boundBox.width; x++) {
        if (mask.contains(x, y)) {
          setTileAt(x, y, ((TileLayer) other).getTileAt(x, y));
        }
      }
    }
  }
Example #3
0
  // generate the capital by finding the center of the largest landmass.
  // this method can only be called after the AgriculturalUnit's regions have been set.
  private MapPoint calCapitolLocation() {
    if (entities == null) throw new RuntimeException("(!) regions not set!");
    if (entities.isEmpty()) throw new RuntimeException("(!) no regions !");

    int maxArea = 0;
    Area largest = null;

    for (AgriculturalUnit region : entities) {
      Area poly = region.getArea();
      int area = (int) (poly.getBounds().getWidth() * poly.getBounds().getHeight());
      if (area >= maxArea) {
        largest = poly;
        maxArea = area;
      }
    }

    int x = (int) largest.getBounds().getCenterX();
    int y = (int) largest.getBounds().getCenterY();

    return AgriculturalUnit.converter.pointToMapPoint(new Point(x, y));
  }
Example #4
0
 public CanBeCutObject(Area area, double x, double y, double vx, double vy) {
   for (int i = 0; i < 3; i++) {
     this.x[i] = x;
     this.y[i] = y;
     this.vx[i] = vx;
     this.vy[i] = vy;
   }
   this.area = area;
   formerArea = computeArea(area.getBounds());
   asMove1.translate(this.x[0], this.y[0]);
   this.area = new Area(asMove1.createTransformedShape(area));
 }
Example #5
0
  /**
   * Like mergeOnto, but will only copy the area specified.
   *
   * @see TileLayer#mergeOnto(MapLayer)
   * @param other
   * @param mask
   */
  @Override
  public void maskedMergeOnto(MapLayer other, Area mask) {
    Rectangle boundBox = mask.getBounds();

    for (int y = boundBox.y; y < boundBox.y + boundBox.height; y++) {
      for (int x = boundBox.x; x < boundBox.x + boundBox.width; x++) {
        Tile tile = ((TileLayer) other).getTileAt(x, y);
        if (mask.contains(x, y) && tile != null) {
          setTileAt(x, y, tile);
        }
      }
    }
  }
Example #6
0
  // generate the capital by finding the center of the largest landmass.
  // this method can only be called after the Territory's regions have been set.
  private MapPoint calCapitolLocation() {
    if (regions == null) throw new RuntimeException("(!) regions not set!");
    if (regions.isEmpty()) throw new RuntimeException("(!) no regions !");

    int maxArea = 0;
    Area largest = null;

    for (GeographicArea region : regions) {
      Area poly = new Area(GeographicArea.mapConverter.regionToPolygon(region));
      int area = (int) (poly.getBounds().getWidth() * poly.getBounds().getHeight());
      if (area >= maxArea) {
        largest = poly;
        maxArea = area;
      }
    }

    if (largest == null) throw new IllegalStateException("Internal error computing largest region");

    int x = (int) largest.getBounds().getCenterX();
    int y = (int) largest.getBounds().getCenterY();

    return Territory.converter.pointToMapPoint(new Point(x, y));
  }
Example #7
0
 /**
  * Area "a" contains the hull that we would like to download data for. however we can only
  * download rectangles, so the following is an attempt at finding a number of rectangles to
  * download.
  *
  * <p>The idea is simply: Start out with the full bounding box. If it is too large, then split it
  * in half and repeat recursively for each half until you arrive at something small enough to
  * download. The algorithm is improved by always using the intersection between the rectangle and
  * the actual desired area. For example, if you have a track that goes like this: +----+ | /| | /
  * | | / | |/ | +----+ then we would first look at downloading the whole rectangle (assume it's
  * too big), after that we split it in half (upper and lower half), but we donot request the full
  * upper and lower rectangle, only the part of the upper/lower rectangle that actually has
  * something in it.
  *
  * <p>This functions calculates the rectangles, asks the user to continue and downloads the areas
  * if applicable.
  */
 protected static void confirmAndDownloadAreas(
     Area a,
     double max_area,
     boolean osmDownload,
     boolean gpxDownload,
     String title,
     ProgressMonitor progressMonitor) {
   List<Rectangle2D> toDownload = new ArrayList<Rectangle2D>();
   addToDownload(a, a.getBounds(), toDownload, max_area);
   if (toDownload.isEmpty()) {
     return;
   }
   JPanel msg = new JPanel(new GridBagLayout());
   msg.add(
       new JLabel(
           tr(
               "<html>This action will require {0} individual<br>"
                   + "download requests. Do you wish<br>to continue?</html>",
               toDownload.size())),
       GBC.eol());
   if (JOptionPane.OK_OPTION
       != JOptionPane.showConfirmDialog(
           Main.parent, msg, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE)) {
     return;
   }
   final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(tr("Download data"));
   final Future<?> future =
       new DownloadTaskList().download(false, toDownload, osmDownload, gpxDownload, monitor);
   Main.worker.submit(
       new Runnable() {
         @Override
         public void run() {
           try {
             future.get();
           } catch (Exception e) {
             e.printStackTrace();
             return;
           }
           monitor.close();
         }
       });
 }
Example #8
0
  /**
   * Tests if two polygons intersect.
   *
   * @param first
   * @param second
   * @return intersection kind
   */
  public static PolygonIntersection polygonIntersection(List<Node> first, List<Node> second) {

    Area a1 = getArea(first);
    Area a2 = getArea(second);

    Area inter = new Area(a1);
    inter.intersect(a2);

    Rectangle bounds = inter.getBounds();

    if (inter.isEmpty() || bounds.getHeight() * bounds.getWidth() <= 1.0) {
      return PolygonIntersection.OUTSIDE;
    } else if (inter.equals(a1)) {
      return PolygonIntersection.FIRST_INSIDE_SECOND;
    } else if (inter.equals(a2)) {
      return PolygonIntersection.SECOND_INSIDE_FIRST;
    } else {
      return PolygonIntersection.CROSSING;
    }
  }
  /**
   * Creates a master shape of the letter.
   *
   * @param shape
   * @return the master shape
   */
  private final Master createMaster(RenderContext ctx, Shape shape, double ascent) {
    final Area area = new Area(shape);
    final double scale = MASTER_HEIGHT / ascent;

    area.transform(AffineTransform.getScaleInstance(scale, scale));
    final Rectangle bounds = area.getBounds();
    // System.out.println("createMaster bounds " + bounds);
    // area.transform(AffineTransform.getTranslateInstance(-bounds.getMinX(),
    // -bounds.getMinY()));
    // bounds = area.getBounds();

    final int minX = (int) (bounds.getMinX() - 0.5);
    final int maxX = (int) (bounds.getMaxX() + 0.5);
    final int minY = (int) (bounds.getMinY() - 0.5);
    final int maxY = (int) (bounds.getMaxY() + 0.5);
    final int width = maxX - minX;
    final int height = maxY - minY;

    BitSet bits = (BitSet) ctx.getObject(BITS_NAME);
    if (bits == null) {
      bits = new BitSet(width * height);
      ctx.setObject(BITS_NAME, bits);
    } else {
      bits.clear();
    }
    int ofs = 0;
    for (int y = maxY; y > minY; y--) {
      for (int x = minX; x < maxX; x++) {
        if (area.contains(x, y)) {
          bits.set(ofs);
        }
        ofs++;
      }
    }

    return new Master(bits, width, height, minX, minY);
  }
  @Override
  public void draw(
      Graphics2D g2d,
      ComponentState componentState,
      boolean outlineMode,
      Project project,
      IDrawingObserver drawingObserver) {
    if (checkPointsClipped(g2d.getClip())) {
      return;
    }
    int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2;
    Area mainArea = getBody();
    Composite oldComposite = g2d.getComposite();
    if (alpha < MAX_ALPHA) {
      g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
    }
    g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor);
    g2d.fill(mainArea);
    g2d.setComposite(oldComposite);
    Color finalBorderColor;
    Theme theme =
        (Theme)
            ConfigurationManager.getInstance()
                .readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
    if (outlineMode) {
      finalBorderColor =
          componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
              ? SELECTION_COLOR
              : theme.getOutlineColor();
    } else {
      finalBorderColor =
          componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
              ? SELECTION_COLOR
              : borderColor;
    }
    g2d.setColor(finalBorderColor);
    g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
    g2d.draw(mainArea);

    for (Point point : controlPoints) {
      if (!outlineMode) {
        g2d.setColor(PIN_COLOR);
        g2d.fillOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize);
      }
      g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR);
      g2d.drawOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize);
    }

    // Draw label.
    g2d.setFont(LABEL_FONT);
    Color finalLabelColor;
    if (outlineMode) {
      finalLabelColor =
          componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
              ? LABEL_COLOR_SELECTED
              : theme.getOutlineColor();
    } else {
      finalLabelColor =
          componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
              ? LABEL_COLOR_SELECTED
              : getLabelColor();
    }
    g2d.setColor(finalLabelColor);
    String label = (getDisplay() == Display.NAME) ? getName() : getValue();
    FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont());
    Rectangle2D rect = fontMetrics.getStringBounds(label, g2d);
    int textHeight = (int) (rect.getHeight());
    int textWidth = (int) (rect.getWidth());
    // Center text horizontally and vertically
    Rectangle bounds = mainArea.getBounds();
    int x = bounds.x + (bounds.width - textWidth) / 2;
    int y = bounds.y + (bounds.height - textHeight) / 2 + fontMetrics.getAscent();
    g2d.drawString(label, x, y);
  }
Example #11
0
  protected void cutTheArea(ArrayList<Point2D> sawtooth) {
    // TODO Auto-generated method stub

    int x = (int) pointList.get(0).getX() - (int) pointList.get(pointList.size() - 1).getX();
    int y = (int) pointList.get(0).getY() - (int) pointList.get(pointList.size() - 1).getY();

    int formerX = (int) pointList.get(pointList.size() - 1).getX();
    int formerY = (int) pointList.get(pointList.size() - 1).getY();

    // 切割添加的第一个点,为水滴离开时的点,延切割方向平移一大段距离
    Point2D firstPoint = new Point(formerX - 10 * x, formerY - 10 * y);
    sawtooth.add(firstPoint);

    // 假如方向为从左上穿过到右下, 先右移一个很大的值,再上移一个很大的值
    int xDirection = 1;
    int yDirection = 1;
    if (x < 0) { // 使其与x,y同号
      xDirection = -1;
    }

    sawtooth.add(new Point((int) firstPoint.getX() - xDirection * 1000, (int) firstPoint.getY()));
    sawtooth.add(
        new Point(
            (int) firstPoint.getX() - xDirection * 1000,
            (int) firstPoint.getY() - yDirection * 5000));
    sawtooth.add(
        new Point(
            (int) firstPoint.getX() + xDirection * 2000,
            (int) firstPoint.getY() - yDirection * 5000));

    formerX = (int) pointList.get(0).getX();
    formerY = (int) pointList.get(0).getY();

    // 切割添加的最后一个点,为水滴离开时的点,延切割反方向平移一大段距离
    Point2D lastPoint = new Point(formerX + 10 * x, formerY + 10 * y);
    sawtooth.add(lastPoint);

    xList = new int[sawtooth.size()];
    yList = new int[sawtooth.size()];

    // 为了多边形的声明,将x,y坐标都变成一个int[]
    for (int i = 0; i < sawtooth.size(); i++) {

      xList[i] = (int) sawtooth.get(i).getX();
      yList[i] = (int) sawtooth.get(i).getY();
    }

    // 开始切割
    Polygon cutPolygon = new Polygon(xList, yList, sawtooth.size());
    Area cutArea = new Area(cutPolygon);

    cutArea.intersect(area); // 这里cutArea是切下来的部分,永远靠上
    area.subtract(cutArea); // 这里area是剩下的部分,靠下

    // 如果被切下来部分的面积大于原面积的0.75,那么把cutArea1变为另一部分
    // ,把原area变为该area,假如两个都不大于原来面积的0.75,那么都变为cutArea(即将消失的部分)
    // 顺便把每一部分的速度改一下,速度是将水滴的速度方向向上旋转30°,和向下旋转30°,生成两个新的速度向量,叠加到原来的速度上。

    // 生成两个新向量,式子是通过方程推导出来的,index 0为靠下部分速度,1为靠上部分速度
    double[] deltavx = {
      Math.sqrt(3) * waterDrop_vx * 0.5
          - 0.5 * (Math.abs(waterDrop_vx) / waterDrop_vx) * waterDrop_vy,
      Math.sqrt(3) * waterDrop_vx * 0.5
          + 0.5 * (Math.abs(waterDrop_vx) / waterDrop_vx) * waterDrop_vy
    };

    double[] deltavy = {
      Math.sqrt(3) * waterDrop_vy * 0.5 + 0.5 * (Math.abs(waterDrop_vx)),
      Math.sqrt(3) * waterDrop_vy * 0.5 - 0.5 * (Math.abs(waterDrop_vx))
    };

    if ((computeArea(area.getBounds()) < formerArea * 0.3)
        && (computeArea(cutArea.getBounds())) > formerArea * 0.8) {
      cutArea1 = area;
      area = cutArea;
      vx[0] = vx[0] + deltavx[1];
      vy[0] = vy[0] + deltavy[1];
      vx[1] = vx[1] + deltavx[0];
      vy[1] = vy[1] + deltavy[0];

    } else if ((computeArea(cutArea.getBounds()) < formerArea * 0.3)
        && (computeArea(area.getBounds())) > formerArea * 0.8) {
      cutArea1 = cutArea;

      vx[1] = vx[1] + deltavx[1];
      vy[1] = vy[1] + deltavy[1];
      vx[0] = vx[0] + deltavx[0];
      vy[0] = vy[0] + deltavy[0];

    } else {

      cutArea1 = cutArea;
      cutArea2 = area;
      area = new Area();

      vx[1] = vx[1] + deltavx[1];
      vy[1] = vy[1] + deltavy[1];
      vx[2] = vx[2] + deltavx[0];
      vy[2] = vy[2] + deltavy[0];
    }

    pointList = new ArrayList<Point2D>();
    this.sawtooth = new ArrayList<Point2D>();
    isPassed = false;
    sawtoothIndex = 0;
  }
  static void renderTextWithJavaFonts(
      GraphicsState gs,
      DynamicVectorRenderer current,
      int streamType,
      ParserOptions parserOptions,
      PdfFont currentFontData,
      GlyphData glyphData,
      final int Tmode,
      final float currentWidth,
      final boolean isTextShifted,
      final PdfJavaGlyphs glyphs,
      final float[][] Trm) {

    final float actualWidth = glyphData.getActualWidth();

    /** set values used if rendering as well */
    Object transformedGlyph2;
    AffineTransform glyphAt = null;

    final int rawInt = glyphData.getRawInt();

    //
    { // render now
      final boolean isSTD =
          actualWidth > 0
              || DecoderOptions.isRunningOnMac
              || streamType == ValueTypes.FORM
              || StandardFonts.isStandardFont(currentFontData.getBaseFontName(), false)
              || currentFontData.isBrokenFont();

      /** flush cache if needed */
      // if(!DynamicVectorRenderer.newCode2){
      if (glyphs.lastTrm[0][0] != Trm[0][0]
          || glyphs.lastTrm[1][0] != Trm[1][0]
          || glyphs.lastTrm[0][1] != Trm[0][1]
          || glyphs.lastTrm[1][1] != Trm[1][1]) {
        glyphs.lastTrm = Trm;
        glyphs.flush();
      }
      // }

      // either calculate the glyph to draw or reuse if already drawn
      Area glyph = glyphs.getCachedShape(rawInt);
      glyphAt = glyphs.getCachedTransform(rawInt);

      if (glyph == null) {

        double dY = -1, dX = 1, x3 = 0, y3 = 0;

        // allow for text running up the page
        if ((Trm[1][0] < 0 && Trm[0][1] >= 0) || (Trm[0][1] < 0 && Trm[1][0] >= 0)) {
          dX = 1f;
          dY = -1f;
        }

        if (isSTD) {

          glyph = glyphs.getGlyph(rawInt, glyphData.getDisplayValue(), currentWidth);

          // hack to fix problem with Java Arial font
          if (glyph != null && rawInt == 146 && glyphs.isArialInstalledLocally) {
            y3 = -(glyph.getBounds().height - glyph.getBounds().y);
          }
        } else {

          // remap font if needed
          String xx = glyphData.getDisplayValue();

          GlyphVector gv1 = null;

          // do not show CID fonts as Lucida unless match
          if (!glyphs.isCIDFont || glyphs.isCorrupted() || glyphs.isFontInstalled) {
            gv1 = glyphs.getUnscaledFont().createGlyphVector(PdfJavaGlyphs.frc, xx);
          }

          if (gv1 != null) {

            glyph = new Area(gv1.getOutline());

            // put glyph into display position
            double glyphX = gv1.getOutline().getBounds2D().getX();

            // ensure inside box
            x3 = 0;

            if (glyphX < 0) {
              glyphX = -glyphX;

              x3 = glyphX * 2;

              // System.out.println(x3+" "+displayTrm[0][0]+" "+displayTrm[0][0]);

              if (Trm[0][0] > Trm[0][1]) {
                x3 *= Trm[0][0];
              } else {
                x3 *= Trm[0][1];
              }

              // glyphAt =AffineTransform.getTranslateInstance(x3,0);

            }

            final double glyphWidth = gv1.getVisualBounds().getWidth() + (glyphX * 2);
            final double scaleFactor = currentWidth / glyphWidth;
            if (scaleFactor < 1) {
              dX *= scaleFactor;
            }

            if (x3 > 0) {
              x3 *= dX;
            }
          }
        }

        glyphAt =
            new AffineTransform(
                dX * Trm[0][0], dX * Trm[0][1], dY * Trm[1][0], dY * Trm[1][1], x3, y3);
        // create shape for text using transformation to make correct size
        // glyphAt =new AffineTransform(dX* displayTrm[0][0],dX* displayTrm[0][1],dY*
        // displayTrm[1][0],dY* displayTrm[1][1] ,x3, y3);

        // save so we can reuse if it occurs again in this TJ command
        glyphs.setCachedShape(rawInt, glyph, glyphAt);
      }

      if (glyph != null && Tmode == GraphicsState.CLIPTEXT && glyph.getBounds().width > 0) {
          /** support for TR7 */

        final Area glyphShape = (Area) glyph.clone();

        // we need to apply to make it all work
        glyphShape.transform(glyphAt);

        // if its already generated we just need to move it
        if (parserOptions.renderDirectly()) {
          final AffineTransform at2 = AffineTransform.getTranslateInstance(Trm[2][0], (Trm[2][1]));
          glyphShape.transform(at2);
        }

        gs.addClip(glyphShape);

        // current.drawClip(gs,null,false);

        // if(parserOptions.renderDirectly()) {
        glyph = null;
        // }

      }

      transformedGlyph2 = glyph;
    }

    if (transformedGlyph2 != null) {

      final double[] textTrans = new double[6];
      glyphAt.getMatrix(textTrans);

      final int fontSize = glyphData.getFontSize();

      if (parserOptions.useJavaFX()) {
        current.drawEmbeddedText(
            Trm,
            fontSize,
            null,
            null,
            DynamicVectorRenderer.TEXT,
            gs,
            textTrans,
            glyphData.getUnicodeValue(),
            currentFontData,
            -100);
      } else

      // add to renderer
      if (parserOptions.renderDirectly()) {
        current.drawEmbeddedText(
            Trm,
            fontSize,
            null,
            transformedGlyph2,
            DynamicVectorRenderer.TEXT,
            gs,
            textTrans,
            glyphData.getUnicodeValue(),
            currentFontData,
            -100);
      } else {

        if (isTextShifted) {
          current.drawEmbeddedText(
              Trm,
              -fontSize,
              null,
              transformedGlyph2,
              DynamicVectorRenderer.TEXT,
              gs,
              null,
              glyphData.getUnicodeValue(),
              currentFontData,
              -100);
        } else {
          current.drawEmbeddedText(
              Trm,
              fontSize,
              null,
              transformedGlyph2,
              DynamicVectorRenderer.TEXT,
              gs,
              null,
              glyphData.getUnicodeValue(),
              currentFontData,
              -100);
        }
      }
    }
  }
  /**
   * Creates a continuous legend item for one item in dimensionSet, i.e. dimensionSet must be a set
   * containing exactly one value.
   *
   * @param dateFormat format used to format minValue and maxValue as dates, or null if they should
   *     be displayed numerically instead of as dates
   * @throws ChartPlottimeException
   */
  private LegendItem createContinuousLegendItem(
      PlotInstance plotInstance,
      Set<PlotDimension> dimensionSet,
      double minValue,
      double maxValue,
      DateFormat dateFormat) {
    PlotConfiguration plotConfiguration = plotInstance.getCurrentPlotConfigurationClone();
    PlotDimension dimension = dimensionSet.iterator().next();
    DefaultDimensionConfig dimensionConfig =
        (DefaultDimensionConfig) plotConfiguration.getDimensionConfig(dimension);
    DimensionConfigData dimensionConfigData =
        plotInstance.getPlotData().getDimensionConfigData(dimensionConfig);
    // String label = dimensionConfig.getLabel();
    // if(label == null) {
    // label = I18N.getGUILabel("plotter.unnamed_value_label");
    // }
    String label = "";

    if (dimension == PlotDimension.COLOR) {
      ColorProvider colorProvider = dimensionConfigData.getColorProvider();
      if (!colorProvider.supportsNumericalValues()) {
        throw new RuntimeException(
            "Color provider for continuous legend item does not support numerical values.");
      }

      // shape dimensions
      final int width = 50;
      final int height = 10;

      // create item paint

      // first disable logarithmic scale on color provider ( -> linear gradient in legend)
      // ContinuousColorProvider continuousColorProvider = null;
      // if (dimensionConfig.isLogarithmic() && colorProvider instanceof
      // ContinuousColorProvider) {
      // continuousColorProvider = (ContinuousColorProvider)colorProvider;
      // continuousColorProvider.setLogarithmic(false);
      // }

      // calculate gradient
      float fractions[] = new float[width];
      Color colors[] = new Color[width];
      for (int i = 0; i < width; ++i) {

        float fraction = i / (width - 1.0f);
        double fractionValue;
        if (colorProvider instanceof ContinuousColorProvider
            && ((ContinuousColorProvider) colorProvider)
                .isColorMinMaxValueDifferentFromOriginal(
                    ((ContinuousColorProvider) colorProvider).getMinValue(),
                    ((ContinuousColorProvider) colorProvider).getMaxValue())) {
          fractionValue =
              ((ContinuousColorProvider) colorProvider).getMinValue()
                  + fraction
                      * (((ContinuousColorProvider) colorProvider).getMaxValue()
                          - ((ContinuousColorProvider) colorProvider).getMinValue());
        } else {
          fractionValue = minValue + fraction * (maxValue - minValue);
        }
        colors[i] = colorProvider.getColorForValue(fractionValue);
        fractions[i] = fraction;
      }
      LinearGradientPaint shapeFillPaint =
          new LinearGradientPaint(
              new Point(0, 0), new Point(width, 0), fractions, colors, CycleMethod.REPEAT);

      // reset color provider to logarithmic if necessary
      // if (continuousColorProvider != null && dimensionConfig.isLogarithmic()) {
      // continuousColorProvider.setLogarithmic(true);
      // }

      // create item shape
      Rectangle itemShape = new Rectangle(width, height);

      if (colorProvider instanceof ContinuousColorProvider) {
        return createFlankedShapeLegendItem(
            label,
            ((ContinuousColorProvider) colorProvider).getMinValue(),
            ((ContinuousColorProvider) colorProvider).getMaxValue(),
            itemShape,
            shapeFillPaint,
            true,
            dateFormat);
      } else {
        return createFlankedShapeLegendItem(
            label, minValue, maxValue, itemShape, shapeFillPaint, true, dateFormat);
      }
    } else if (dimension == PlotDimension.SHAPE) {
      // shape provider probably never supports numerical values
      return null;
    } else if (dimension == PlotDimension.SIZE) {
      SizeProvider sizeProvider = dimensionConfigData.getSizeProvider();

      if (!sizeProvider.supportsNumericalValues()) {
        throw new RuntimeException(
            "Size provider for continuous legend item does not support numerical values.");
      }

      double minScalingFactor = sizeProvider.getMinScalingFactor();
      double maxScalingFactor = sizeProvider.getMaxScalingFactor();
      ContinuousSizeProvider legendSizeProvider =
          new ContinuousSizeProvider(
              minScalingFactor,
              maxScalingFactor,
              MIN_LEGEND_ITEM_SCALING_FACTOR,
              MAX_LEGEND_ITEM_SCALING_FACTOR,
              false);

      int legendItemCount = 4;
      Area composedShape = new Area();
      Shape originalShape = UNDEFINED_SHAPE;
      if (dimensionSet.contains(PlotDimension.SIZE) && dimensionSet.size() == 1) {
        originalShape = UNDEFINED_SHAPE_AND_COLOR;
      }
      double maxHeight = originalShape.getBounds().getHeight() * MAX_LEGEND_ITEM_SCALING_FACTOR;
      for (int i = 0; i < legendItemCount; ++i) {
        double fraction =
            minScalingFactor
                + ((double) i / legendItemCount * (maxScalingFactor - minScalingFactor));
        double legendScalingFactor = legendSizeProvider.getScalingFactorForValue(fraction);

        double composedWidth = composedShape.getBounds().getWidth();

        AffineTransform t = new AffineTransform();
        t.scale(legendScalingFactor, legendScalingFactor);
        Shape shape = t.createTransformedShape(originalShape);

        t = new AffineTransform();
        double shapeWidth = shape.getBounds().getWidth();
        double shapeHeight = shape.getBounds().getHeight();
        t.translate(composedWidth + shapeWidth * .1, (maxHeight - shapeHeight) / 2.0);
        t.translate(-shape.getBounds().getMinX(), -shape.getBounds().getMinY());
        shape = t.createTransformedShape(shape);
        composedShape.add(new Area(shape));
      }

      return createFlankedShapeLegendItem(
          label, minValue, maxValue, composedShape, UNDEFINED_COLOR_PAINT, false, dateFormat);

    } else {
      throw new RuntimeException(
          "Unsupported dimension. Execution path should never reach this line.");
    }
  }