/**
   * Created an entity for the axis.
   *
   * @param cursor the initial cursor value.
   * @param state the axis state after completion of the drawing with a possibly updated cursor
   *     position.
   * @param dataArea the data area.
   * @param edge the edge.
   * @param plotState the PlotRenderingInfo from which a reference to the entity collection can be
   *     obtained.
   * @since 1.0.13
   */
  protected void createAndAddEntity(
      double cursor,
      AxisState state,
      Rectangle2D dataArea,
      RectangleEdge edge,
      PlotRenderingInfo plotState) {

    if (plotState == null || plotState.getOwner() == null) {
      return; // no need to create entity if we can´t save it anyways...
    }
    Rectangle2D hotspot = null;
    if (edge.equals(RectangleEdge.TOP)) {
      hotspot =
          new Rectangle2D.Double(
              dataArea.getX(), state.getCursor(), dataArea.getWidth(), cursor - state.getCursor());
    } else if (edge.equals(RectangleEdge.BOTTOM)) {
      hotspot =
          new Rectangle2D.Double(
              dataArea.getX(), cursor, dataArea.getWidth(), state.getCursor() - cursor);
    } else if (edge.equals(RectangleEdge.LEFT)) {
      hotspot =
          new Rectangle2D.Double(
              state.getCursor(), dataArea.getY(), cursor - state.getCursor(), dataArea.getHeight());
    } else if (edge.equals(RectangleEdge.RIGHT)) {
      hotspot =
          new Rectangle2D.Double(
              cursor, dataArea.getY(), state.getCursor() - cursor, dataArea.getHeight());
    }
    EntityCollection e = plotState.getOwner().getEntityCollection();
    if (e != null) {
      e.add(new AxisEntity(hotspot, this));
    }
  }
  /**
   * Adds an entity with the specified hotspot, but only if an entity collection is accessible via
   * the renderer state.
   *
   * @param entities the entity collection.
   * @param dataset the dataset.
   * @param row the row index.
   * @param column the column index.
   * @param hotspot the hotspot.
   */
  protected void addItemEntity(
      EntityCollection entities, CategoryDataset dataset, int row, int column, Shape hotspot) {

    String tip = null;
    CategoryToolTipGenerator tipster = getToolTipGenerator(row, column);
    if (tipster != null) {
      tip = tipster.generateToolTip(dataset, row, column);
    }
    String url = null;
    CategoryURLGenerator urlster = getItemURLGenerator(row, column);
    if (urlster != null) {
      url = urlster.generateURL(dataset, row, column);
    }
    CategoryItemEntity entity =
        new CategoryItemEntity(
            hotspot, tip, url, dataset, row, dataset.getColumnKey(column), column);
    entities.add(entity);
  }
 /**
  * Draws the block within the specified area.
  *
  * @param g2  the graphics device.
  * @param area  the area.
  * @param params  passed on to blocks within the container
  *                (<code>null</code> permitted).
  *
  * @return An instance of {@link EntityBlockResult}, or <code>null</code>.
  */
 public Object draw(Graphics2D g2, Rectangle2D area, Object params) {
     // draw the block without collecting entities
     super.draw(g2, area, null);
     EntityBlockParams ebp = null;
     BlockResult r = new BlockResult();
     if (params instanceof EntityBlockParams) {
         ebp = (EntityBlockParams) params;
         if (ebp.getGenerateEntities()) {
             EntityCollection ec = new StandardEntityCollection();
             LegendItemEntity entity = new LegendItemEntity(
                     (Shape) area.clone());
             entity.setSeriesIndex(this.series);
             entity.setSeriesKey(this.seriesKey);
             entity.setDataset(this.dataset);
             entity.setToolTipText(getToolTipText());
             entity.setURLText(getURLText());
             ec.add(entity);
             r.setEntityCollection(ec);
         }
     }
     return r;
 }
  /**
   * Draws the visual representation of a single data item, second pass. In the second pass, the
   * renderer draws the lines and shapes for the individual points in the two series.
   *
   * @param x_graphics the graphics device.
   * @param x_dataArea the area within which the data is being drawn.
   * @param x_info collects information about the drawing.
   * @param x_plot the plot (can be used to obtain standard color information etc).
   * @param x_domainAxis the domain (horizontal) axis.
   * @param x_rangeAxis the range (vertical) axis.
   * @param x_dataset the dataset.
   * @param x_series the series index (zero-based).
   * @param x_item the item index (zero-based).
   * @param x_crosshairState crosshair information for the plot (<code>null</code> permitted).
   */
  protected void drawItemPass1(
      Graphics2D x_graphics,
      Rectangle2D x_dataArea,
      PlotRenderingInfo x_info,
      XYPlot x_plot,
      ValueAxis x_domainAxis,
      ValueAxis x_rangeAxis,
      XYDataset x_dataset,
      int x_series,
      int x_item,
      CrosshairState x_crosshairState) {

    Shape l_entityArea = null;
    EntityCollection l_entities = null;
    if (null != x_info) {
      l_entities = x_info.getOwner().getEntityCollection();
    }

    Paint l_seriesPaint = getItemPaint(x_series, x_item);
    Stroke l_seriesStroke = getItemStroke(x_series, x_item);
    x_graphics.setPaint(l_seriesPaint);
    x_graphics.setStroke(l_seriesStroke);

    PlotOrientation l_orientation = x_plot.getOrientation();
    RectangleEdge l_domainAxisLocation = x_plot.getDomainAxisEdge();
    RectangleEdge l_rangeAxisLocation = x_plot.getRangeAxisEdge();

    double l_x0 = x_dataset.getXValue(x_series, x_item);
    double l_y0 = x_dataset.getYValue(x_series, x_item);
    double l_x1 = x_domainAxis.valueToJava2D(l_x0, x_dataArea, l_domainAxisLocation);
    double l_y1 = x_rangeAxis.valueToJava2D(l_y0, x_dataArea, l_rangeAxisLocation);

    if (getShapesVisible()) {
      Shape l_shape = getItemShape(x_series, x_item);
      if (l_orientation == PlotOrientation.HORIZONTAL) {
        l_shape = ShapeUtilities.createTranslatedShape(l_shape, l_y1, l_x1);
      } else {
        l_shape = ShapeUtilities.createTranslatedShape(l_shape, l_x1, l_y1);
      }
      if (l_shape.intersects(x_dataArea)) {
        x_graphics.setPaint(getItemPaint(x_series, x_item));
        x_graphics.fill(l_shape);
      }
      l_entityArea = l_shape;
    }

    // add an entity for the item...
    if (null != l_entities) {
      if (null == l_entityArea) {
        l_entityArea = new Rectangle2D.Double((l_x1 - 2), (l_y1 - 2), 4, 4);
      }
      String l_tip = null;
      XYToolTipGenerator l_tipGenerator = getToolTipGenerator(x_series, x_item);
      if (null != l_tipGenerator) {
        l_tip = l_tipGenerator.generateToolTip(x_dataset, x_series, x_item);
      }
      String l_url = null;
      XYURLGenerator l_urlGenerator = getURLGenerator();
      if (null != l_urlGenerator) {
        l_url = l_urlGenerator.generateURL(x_dataset, x_series, x_item);
      }
      XYItemEntity l_entity =
          new XYItemEntity(l_entityArea, x_dataset, x_series, x_item, l_tip, l_url);
      l_entities.add(l_entity);
    }

    // draw the item label if there is one...
    if (isItemLabelVisible(x_series, x_item)) {
      drawItemLabel(
          x_graphics, l_orientation, x_dataset, x_series, x_item, l_x1, l_y1, (l_y1 < 0.0));
    }

    int l_domainAxisIndex = x_plot.getDomainAxisIndex(x_domainAxis);
    int l_rangeAxisIndex = x_plot.getRangeAxisIndex(x_rangeAxis);
    updateCrosshairValues(
        x_crosshairState,
        l_x0,
        l_y0,
        l_domainAxisIndex,
        l_rangeAxisIndex,
        l_x1,
        l_y1,
        l_orientation);

    if (0 == x_item) {
      return;
    }

    double l_x2 =
        x_domainAxis.valueToJava2D(
            x_dataset.getXValue(x_series, (x_item - 1)), x_dataArea, l_domainAxisLocation);
    double l_y2 =
        x_rangeAxis.valueToJava2D(
            x_dataset.getYValue(x_series, (x_item - 1)), x_dataArea, l_rangeAxisLocation);

    Line2D l_line = null;
    if (PlotOrientation.HORIZONTAL == l_orientation) {
      l_line = new Line2D.Double(l_y1, l_x1, l_y2, l_x2);
    } else if (PlotOrientation.VERTICAL == l_orientation) {
      l_line = new Line2D.Double(l_x1, l_y1, l_x2, l_y2);
    }

    if ((null != l_line) && l_line.intersects(x_dataArea)) {
      x_graphics.setPaint(getItemPaint(x_series, x_item));
      x_graphics.setStroke(getItemStroke(x_series, x_item));
      x_graphics.draw(l_line);
    }
  }
  /**
   * Draws a single data item.
   *
   * @param g2 the graphics device (<code>null</code> not permitted).
   * @param section the section index.
   * @param dataArea the data plot area.
   * @param state state information for one chart.
   * @param currentPass the current pass index.
   */
  protected void drawItem(
      Graphics2D g2, int section, Rectangle2D dataArea, PiePlotState state, int currentPass) {

    PieDataset dataset = getDataset();
    Number n = dataset.getValue(section);
    if (n == null) {
      return;
    }
    double value = n.doubleValue();
    double angle1 = 0.0;
    double angle2 = 0.0;

    Rotation direction = getDirection();
    if (direction == Rotation.CLOCKWISE) {
      angle1 = state.getLatestAngle();
      angle2 = angle1 - value / state.getTotal() * 360.0;
    } else if (direction == Rotation.ANTICLOCKWISE) {
      angle1 = state.getLatestAngle();
      angle2 = angle1 + value / state.getTotal() * 360.0;
    } else {
      throw new IllegalStateException("Rotation type not recognised.");
    }

    double angle = (angle2 - angle1);
    if (Math.abs(angle) > getMinimumArcAngleToDraw()) {
      double ep = 0.0;
      double mep = getMaximumExplodePercent();
      if (mep > 0.0) {
        ep = getExplodePercent(section) / mep;
      }
      Rectangle2D arcBounds =
          getArcBounds(state.getPieArea(), state.getExplodedPieArea(), angle1, angle, ep);
      Arc2D.Double arc = new Arc2D.Double(arcBounds, angle1, angle, Arc2D.OPEN);

      // create the bounds for the inner arc
      RectangleInsets s =
          new RectangleInsets(
              UnitType.RELATIVE, sectionDepth, sectionDepth, sectionDepth, sectionDepth);
      Rectangle2D innerArcBounds = new Rectangle2D.Double();
      innerArcBounds.setRect(arcBounds);
      s.trim(innerArcBounds);
      // calculate inner arc in reverse direction, for later
      // GeneralPath construction
      Arc2D.Double arc2 = new Arc2D.Double(innerArcBounds, angle1 + angle, -angle, Arc2D.OPEN);
      GeneralPath path = new GeneralPath();
      path.moveTo((float) arc.getStartPoint().getX(), (float) arc.getStartPoint().getY());
      path.append(arc.getPathIterator(null), false);
      path.append(arc2.getPathIterator(null), true);
      path.closePath();

      Line2D separator = new Line2D.Double(arc2.getEndPoint(), arc.getStartPoint());

      if (currentPass == 0) {
        Paint shadowPaint = getShadowPaint();
        double shadowXOffset = getShadowXOffset();
        double shadowYOffset = getShadowYOffset();
        if (shadowPaint != null) {
          Shape shadowArc =
              ShapeUtilities.createTranslatedShape(
                  path, (float) shadowXOffset, (float) shadowYOffset);
          g2.setPaint(shadowPaint);
          g2.fill(shadowArc);
        }
      } else if (currentPass == 1) {

        Paint paint = getSectionPaint(section);
        g2.setPaint(paint);
        g2.fill(path);
        Paint outlinePaint = getSectionOutlinePaint(section);
        Stroke outlineStroke = getSectionOutlineStroke(section);
        if (getSectionOutlinesVisible()) {
          g2.setPaint(outlinePaint);
          g2.setStroke(outlineStroke);
          g2.draw(path);
        }

        // add an entity for the pie section
        if (state.getInfo() != null) {
          EntityCollection entities = state.getEntityCollection();
          if (entities != null) {
            Comparable key = dataset.getKey(section);
            String tip = null;
            PieToolTipGenerator toolTipGenerator = getToolTipGenerator();
            if (toolTipGenerator != null) {
              tip = toolTipGenerator.generateToolTip(dataset, key);
            }
            String url = null;
            PieURLGenerator urlGenerator = getURLGenerator();
            if (urlGenerator != null) {
              url = urlGenerator.generateURL(dataset, key, getPieIndex());
            }
            PieSectionEntity entity =
                new PieSectionEntity(path, dataset, getPieIndex(), section, key, tip, url);
            entities.add(entity);
          }
        }
      } else if (currentPass == 2) {
        // if there were 3 passes...
        if (this.sectionSeparatorsVisible) {
          Line2D extendedSeparator =
              extendLine(separator, this.innerSeparatorExtension, this.outerSeparatorExtension);
          g2.setStroke(this.separatorStroke);
          g2.setPaint(this.separatorPaint);
          g2.draw(extendedSeparator);
        }
      }
    }
    state.setLatestAngle(angle2);
  }
  /**
   * Draws the category labels and returns the updated axis state.
   *
   * @param g2 the graphics device (<code>null</code> not permitted).
   * @param plotArea the plot area (<code>null</code> not permitted).
   * @param dataArea the area inside the axes (<code>null</code> not permitted).
   * @param edge the axis location (<code>null</code> not permitted).
   * @param state the axis state (<code>null</code> not permitted).
   * @param plotState collects information about the plot (<code>null</code> permitted).
   * @return The updated axis state (never <code>null</code>).
   */
  protected AxisState drawCategoryLabels(
      Graphics2D g2,
      Rectangle2D plotArea,
      Rectangle2D dataArea,
      RectangleEdge edge,
      AxisState state,
      PlotRenderingInfo plotState) {

    ParamChecks.nullNotPermitted(state, "state");
    if (!isTickLabelsVisible()) {
      return state;
    }
    List<CategoryTick> ticks = refreshTicks(g2, state, plotArea, edge);
    // state.setTicks(ticks);        //FIXME MMC had to remove this as the types don't match

    int categoryIndex = 0;
    for (CategoryTick tick : ticks) {

      g2.setFont(getTickLabelFont(tick.getCategory()));
      g2.setPaint(getTickLabelPaint(tick.getCategory()));

      CategoryLabelPosition position = this.categoryLabelPositions.getLabelPosition(edge);
      double x0 = 0.0;
      double x1 = 0.0;
      double y0 = 0.0;
      double y1 = 0.0;
      if (edge == RectangleEdge.TOP) {
        x0 = getCategoryStart(categoryIndex, ticks.size(), dataArea, edge);
        x1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea, edge);
        y1 = state.getCursor() - this.categoryLabelPositionOffset;
        y0 = y1 - state.getMax();
      } else if (edge == RectangleEdge.BOTTOM) {
        x0 = getCategoryStart(categoryIndex, ticks.size(), dataArea, edge);
        x1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea, edge);
        y0 = state.getCursor() + this.categoryLabelPositionOffset;
        y1 = y0 + state.getMax();
      } else if (edge == RectangleEdge.LEFT) {
        y0 = getCategoryStart(categoryIndex, ticks.size(), dataArea, edge);
        y1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea, edge);
        x1 = state.getCursor() - this.categoryLabelPositionOffset;
        x0 = x1 - state.getMax();
      } else if (edge == RectangleEdge.RIGHT) {
        y0 = getCategoryStart(categoryIndex, ticks.size(), dataArea, edge);
        y1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea, edge);
        x0 = state.getCursor() + this.categoryLabelPositionOffset;
        x1 = x0 - state.getMax();
      }
      Rectangle2D area = new Rectangle2D.Double(x0, y0, (x1 - x0), (y1 - y0));
      Point2D anchorPoint = RectangleAnchor.coordinates(area, position.getCategoryAnchor());
      TextBlock block = tick.getLabel();
      block.draw(
          g2,
          (float) anchorPoint.getX(),
          (float) anchorPoint.getY(),
          position.getLabelAnchor(),
          (float) anchorPoint.getX(),
          (float) anchorPoint.getY(),
          position.getAngle());
      Shape bounds =
          block.calculateBounds(
              g2,
              (float) anchorPoint.getX(),
              (float) anchorPoint.getY(),
              position.getLabelAnchor(),
              (float) anchorPoint.getX(),
              (float) anchorPoint.getY(),
              position.getAngle());
      if (plotState != null && plotState.getOwner() != null) {
        EntityCollection entities = plotState.getOwner().getEntityCollection();
        if (entities != null) {
          String tooltip = getCategoryLabelToolTip(tick.getCategory());
          String url = getCategoryLabelURL(tick.getCategory());
          entities.add(new CategoryLabelEntity(tick.getCategory(), bounds, tooltip, url));
        }
      }
      categoryIndex++;
    }

    if (edge.equals(RectangleEdge.TOP)) {
      double h = state.getMax() + this.categoryLabelPositionOffset;
      state.cursorUp(h);
    } else if (edge.equals(RectangleEdge.BOTTOM)) {
      double h = state.getMax() + this.categoryLabelPositionOffset;
      state.cursorDown(h);
    } else if (edge == RectangleEdge.LEFT) {
      double w = state.getMax() + this.categoryLabelPositionOffset;
      state.cursorLeft(w);
    } else if (edge == RectangleEdge.RIGHT) {
      double w = state.getMax() + this.categoryLabelPositionOffset;
      state.cursorRight(w);
    }
    return state;
  }
  /**
   * Draws the visual representation of a single data item.
   *
   * @param g2 the graphics device.
   * @param state the renderer state.
   * @param dataArea the area within which the data is being drawn.
   * @param info collects information about the drawing.
   * @param plot the plot (can be used to obtain standard color information etc).
   * @param domainAxis the domain axis.
   * @param rangeAxis the range axis.
   * @param dataset the dataset.
   * @param series the series index (zero-based).
   * @param item the item index (zero-based).
   * @param crosshairState crosshair information for the plot (<code>null</code> permitted).
   * @param pass the pass index.
   */
  public void drawItem(
      Graphics2D g2,
      XYItemRendererState state,
      Rectangle2D dataArea,
      PlotRenderingInfo info,
      XYPlot plot,
      ValueAxis domainAxis,
      ValueAxis rangeAxis,
      XYDataset dataset,
      int series,
      int item,
      CrosshairState crosshairState,
      int pass) {

    if (!getItemVisible(series, item)) {
      return;
    }
    XYAreaRendererState areaState = (XYAreaRendererState) state;

    // get the data point...
    double x1 = dataset.getXValue(series, item);
    double y1 = dataset.getYValue(series, item);
    if (Double.isNaN(y1)) {
      y1 = 0.0;
    }
    double transX1 = domainAxis.valueToJava2D(x1, dataArea, plot.getDomainAxisEdge());
    double transY1 = rangeAxis.valueToJava2D(y1, dataArea, plot.getRangeAxisEdge());

    // get the previous point and the next point so we can calculate a
    // "hot spot" for the area (used by the chart entity)...
    int itemCount = dataset.getItemCount(series);
    double x0 = dataset.getXValue(series, Math.max(item - 1, 0));
    double y0 = dataset.getYValue(series, Math.max(item - 1, 0));
    if (Double.isNaN(y0)) {
      y0 = 0.0;
    }
    double transX0 = domainAxis.valueToJava2D(x0, dataArea, plot.getDomainAxisEdge());
    double transY0 = rangeAxis.valueToJava2D(y0, dataArea, plot.getRangeAxisEdge());

    double x2 = dataset.getXValue(series, Math.min(item + 1, itemCount - 1));
    double y2 = dataset.getYValue(series, Math.min(item + 1, itemCount - 1));
    if (Double.isNaN(y2)) {
      y2 = 0.0;
    }
    double transX2 = domainAxis.valueToJava2D(x2, dataArea, plot.getDomainAxisEdge());
    double transY2 = rangeAxis.valueToJava2D(y2, dataArea, plot.getRangeAxisEdge());

    double transZero = rangeAxis.valueToJava2D(0.0, dataArea, plot.getRangeAxisEdge());
    Polygon hotspot = null;
    if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
      hotspot = new Polygon();
      hotspot.addPoint((int) transZero, (int) ((transX0 + transX1) / 2.0));
      hotspot.addPoint((int) ((transY0 + transY1) / 2.0), (int) ((transX0 + transX1) / 2.0));
      hotspot.addPoint((int) transY1, (int) transX1);
      hotspot.addPoint((int) ((transY1 + transY2) / 2.0), (int) ((transX1 + transX2) / 2.0));
      hotspot.addPoint((int) transZero, (int) ((transX1 + transX2) / 2.0));
    } else { // vertical orientation
      hotspot = new Polygon();
      hotspot.addPoint((int) ((transX0 + transX1) / 2.0), (int) transZero);
      hotspot.addPoint((int) ((transX0 + transX1) / 2.0), (int) ((transY0 + transY1) / 2.0));
      hotspot.addPoint((int) transX1, (int) transY1);
      hotspot.addPoint((int) ((transX1 + transX2) / 2.0), (int) ((transY1 + transY2) / 2.0));
      hotspot.addPoint((int) ((transX1 + transX2) / 2.0), (int) transZero);
    }

    if (item == 0) { // create a new area polygon for the series
      areaState.area = new Polygon();
      // the first point is (x, 0)
      double zero = rangeAxis.valueToJava2D(0.0, dataArea, plot.getRangeAxisEdge());
      if (plot.getOrientation() == PlotOrientation.VERTICAL) {
        areaState.area.addPoint((int) transX1, (int) zero);
      } else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
        areaState.area.addPoint((int) zero, (int) transX1);
      }
    }

    // Add each point to Area (x, y)
    if (plot.getOrientation() == PlotOrientation.VERTICAL) {
      areaState.area.addPoint((int) transX1, (int) transY1);
    } else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
      areaState.area.addPoint((int) transY1, (int) transX1);
    }

    PlotOrientation orientation = plot.getOrientation();
    Paint paint = getItemPaint(series, item);
    Stroke stroke = getItemStroke(series, item);
    g2.setPaint(paint);
    g2.setStroke(stroke);

    Shape shape = null;
    if (getPlotShapes()) {
      shape = getItemShape(series, item);
      if (orientation == PlotOrientation.VERTICAL) {
        shape = ShapeUtilities.createTranslatedShape(shape, transX1, transY1);
      } else if (orientation == PlotOrientation.HORIZONTAL) {
        shape = ShapeUtilities.createTranslatedShape(shape, transY1, transX1);
      }
      g2.draw(shape);
    }

    if (getPlotLines()) {
      if (item > 0) {
        if (plot.getOrientation() == PlotOrientation.VERTICAL) {
          areaState.line.setLine(transX0, transY0, transX1, transY1);
        } else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
          areaState.line.setLine(transY0, transX0, transY1, transX1);
        }
        g2.draw(areaState.line);
      }
    }

    // Check if the item is the last item for the series.
    // and number of items > 0.  We can't draw an area for a single point.
    if (getPlotArea() && item > 0 && item == (itemCount - 1)) {

      if (orientation == PlotOrientation.VERTICAL) {
        // Add the last point (x,0)
        areaState.area.addPoint((int) transX1, (int) transZero);
      } else if (orientation == PlotOrientation.HORIZONTAL) {
        // Add the last point (x,0)
        areaState.area.addPoint((int) transZero, (int) transX1);
      }

      g2.fill(areaState.area);

      // draw an outline around the Area.
      if (isOutline()) {
        g2.setStroke(getItemOutlineStroke(series, item));
        g2.setPaint(getItemOutlinePaint(series, item));
        g2.draw(areaState.area);
      }
    }

    updateCrosshairValues(crosshairState, x1, y1, transX1, transY1, orientation);

    // collect entity and tool tip information...
    if (state.getInfo() != null) {
      EntityCollection entities = state.getEntityCollection();
      if (entities != null && hotspot != null) {
        String tip = null;
        XYToolTipGenerator generator = getToolTipGenerator(series, item);
        if (generator != null) {
          tip = generator.generateToolTip(dataset, series, item);
        }
        String url = null;
        if (getURLGenerator() != null) {
          url = getURLGenerator().generateURL(dataset, series, item);
        }
        XYItemEntity entity = new XYItemEntity(hotspot, dataset, series, item, tip, url);
        entities.add(entity);
      }
    }
  }