/**
  * Get the bounding box of the shape when stroked. This method takes account of the thickness of
  * the stroke.
  */
 public Rectangle2D getBounds() {
   // FIXME: these bounds REALLY need to be cached.  But it's
   // painful because of the public members.
   if (stroke == null) {
     return shape.getBounds2D();
   } else if (stroke instanceof BasicStroke) {
     // For some reason (antialiasing?) the bounds returned by
     // BasicStroke is off by one.  This code works around it.
     // if all we want is the bounds, then we don't need to actually
     // stroke the shape.  We've had reports that this is no longer
     // necessary with JDK1.3.
     Rectangle2D rect = shape.getBounds2D();
     int width = (int) ((BasicStroke) stroke).getLineWidth() + 2;
     return new Rectangle2D.Double(
         rect.getX() - width,
         rect.getY() - width,
         rect.getWidth() + width + width,
         rect.getHeight() + width + width);
   } else {
     // For some reason (antialiasing?) the bounds returned by
     // BasicStroke is off by one.  This code works around it.
     // We've had reports that this is no longer
     // necessary with JDK1.3.
     Rectangle2D rect = stroke.createStrokedShape(shape).getBounds2D();
     return new Rectangle2D.Double(
         rect.getX() - 1, rect.getY() - 1, rect.getWidth() + 2, rect.getHeight() + 2);
   }
 }
 public String toString() {
   return "LabelPoint"
       + name
       + "\n\tanchorPoint=>("
       + anchorPoint.getX()
       + ", "
       + anchorPoint.getY()
       + ")"
       + "\n\tgetMinX()=>"
       + (bounds.getBounds2D()).getMinX()
       + " getMaxX()=>"
       + (bounds.getBounds2D()).getMaxX();
 }
Beispiel #3
0
  @Override
  public Shape getPointShape(PointData data) {
    Row row = data.row;
    int colLabel = getColumn();
    if (colLabel >= row.size()) {
      return null;
    }

    Comparable<?> labelValue = row.get(colLabel);
    if (labelValue == null) {
      return null;
    }

    Format format = getFormat();
    Font font = getFont();
    String text = format.format(labelValue);
    double alignment = getAlignmentX();
    Shape shape = GraphicsUtils.getOutline(text, font, 0f, alignment);

    double alignX = getAlignmentX();
    double alignY = getAlignmentY();
    Rectangle2D bounds = shape.getBounds2D();
    AffineTransform tx =
        AffineTransform.getTranslateInstance(
            -alignX * bounds.getWidth(), alignY * bounds.getHeight());
    shape = tx.createTransformedShape(shape);

    return shape;
  }
 /**
  * Transforms a <code>GradientPaint</code> instance to fit the specified
  * <code>target</code> shape.
  * 
  * @param paint  the original paint (<code>null</code> not permitted).
  * @param target  the target shape (<code>null</code> not permitted).
  * 
  * @return The transformed paint.
  */
 public GradientPaint transform(final GradientPaint paint, 
                                final Shape target) {
     
     GradientPaint result = paint;
     final Rectangle2D bounds = target.getBounds2D();
     
     if (this.type.equals(GradientPaintTransformType.VERTICAL)) {
         result = new GradientPaint((float) bounds.getCenterX(), 
                 (float) bounds.getMinY(), paint.getColor1(), 
                 (float) bounds.getCenterX(), (float) bounds.getMaxY(), 
                 paint.getColor2());
     }
     else if (this.type.equals(GradientPaintTransformType.HORIZONTAL)) {
         result = new GradientPaint((float) bounds.getMinX(), 
                 (float) bounds.getCenterY(), paint.getColor1(), 
                 (float) bounds.getMaxX(), (float) bounds.getCenterY(), 
                 paint.getColor2());            
     }
     else if (this.type.equals(
             GradientPaintTransformType.CENTER_HORIZONTAL)) {
         result = new GradientPaint((float) bounds.getCenterX(), 
                 (float) bounds.getCenterY(), paint.getColor2(), 
                 (float) bounds.getMaxX(), (float) bounds.getCenterY(), 
                 paint.getColor1(), true);            
     }
     else if (this.type.equals(GradientPaintTransformType.CENTER_VERTICAL)) {
         result = new GradientPaint((float) bounds.getCenterX(), 
                 (float) bounds.getMinY(), paint.getColor1(), 
                 (float) bounds.getCenterX(), (float) bounds.getCenterY(), 
                 paint.getColor2(), true);            
     }
     
     return result;
 }
 private static LegendTitle createLegend(String legend1Text, String legend2Text) {
   final LegendItemCollection legendItems = new LegendItemCollection();
   FontRenderContext frc = new FontRenderContext(null, true, true);
   Font legenfont = new Font(Font.SANS_SERIF, Font.BOLD, 12);
   GlyphVector gv = legenfont.createGlyphVector(frc, new char[] {'X', 'X'});
   Shape shape = gv.getVisualBounds();
   Rectangle2D bounds = shape.getBounds2D();
   HatchedRectangle hatchShape =
       new HatchedRectangle(
           bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), 5, 5);
   {
     LegendItem li = new LegendItem(legend1Text, null, null, null, hatchShape, Color.black);
     li.setLabelFont(legenfont);
     legendItems.add(li);
   }
   {
     LegendItem li = new LegendItem(legend2Text, null, null, null, shape, Color.black);
     li.setLabelFont(legenfont);
     legendItems.add(li);
   }
   LegendTitle legend =
       new LegendTitle(
           new LegendItemSource() {
             @Override
             public LegendItemCollection getLegendItems() {
               return legendItems;
             }
           });
   legend.setPosition(RectangleEdge.BOTTOM);
   legend.setMargin(new RectangleInsets(0, 30, 0, 0));
   legend.setPadding(RectangleInsets.ZERO_INSETS);
   legend.setLegendItemGraphicPadding(new RectangleInsets(0, 20, 0, 0));
   return legend;
 }
 private Paint decodeGradient10(Shape s) {
   Rectangle2D bounds = s.getBounds2D();
   float x = (float) bounds.getX();
   float y = (float) bounds.getY();
   float w = (float) bounds.getWidth();
   float h = (float) bounds.getHeight();
   return decodeGradient(
       (0.5f * w) + x,
       (0.0f * h) + y,
       (0.5f * w) + x,
       (1.0f * h) + y,
       new float[] {0.0f, 0.024f, 0.06f, 0.276f, 0.6f, 0.65f, 0.7f, 0.856f, 0.96f, 0.98f, 1.0f},
       new Color[] {
         (Color) componentColors[0],
         decodeColor((Color) componentColors[0], (Color) componentColors[1], 0.5f),
         (Color) componentColors[1],
         decodeColor((Color) componentColors[1], (Color) componentColors[2], 0.5f),
         (Color) componentColors[2],
         decodeColor((Color) componentColors[2], (Color) componentColors[2], 0.5f),
         (Color) componentColors[2],
         decodeColor((Color) componentColors[2], (Color) componentColors[3], 0.5f),
         (Color) componentColors[3],
         decodeColor((Color) componentColors[3], (Color) componentColors[3], 0.5f),
         (Color) componentColors[3]
       });
 }
 private Paint decodeGradient6(Shape s) {
   Rectangle2D bounds = s.getBounds2D();
   float x = (float) bounds.getX();
   float y = (float) bounds.getY();
   float w = (float) bounds.getWidth();
   float h = (float) bounds.getHeight();
   return decodeGradient(
       (0.5f * w) + x,
       (0.0f * h) + y,
       (0.5f * w) + x,
       (1.0f * h) + y,
       new float[] {0.0f, 0.03f, 0.06f, 0.33f, 0.6f, 0.65f, 0.7f, 0.825f, 0.95f, 0.975f, 1.0f},
       new Color[] {
         color28,
         decodeColor(color28, color29, 0.5f),
         color29,
         decodeColor(color29, color30, 0.5f),
         color30,
         decodeColor(color30, color30, 0.5f),
         color30,
         decodeColor(color30, color31, 0.5f),
         color31,
         decodeColor(color31, color32, 0.5f),
         color32
       });
 }
Beispiel #8
0
  private static boolean _collision(Shape shp1, Shape shp2) {
    // Get shape bounds ...
    Rectangle2D bounds1 = shp1.getBounds2D();
    Rectangle2D bounds2 = shp2.getBounds2D();

    // ... and extend by eps
    bounds1.setFrame(
        bounds1.getX() - mEps,
        bounds1.getY() - mEps,
        bounds1.getWidth() + mEps + mEps,
        bounds1.getHeight() + mEps + mEps);
    bounds2.setFrame(
        bounds2.getX() - mEps,
        bounds2.getY() - mEps,
        bounds2.getWidth() + mEps + mEps,
        bounds2.getHeight() + mEps + mEps);
    return bounds1.intersects(bounds2);
  }
  /**
   * A utility method for determining the height of a text block.
   *
   * @param block the text block.
   * @param position the label position.
   * @param g2 the graphics device.
   * @return The height.
   */
  protected double calculateTextBlockHeight(
      TextBlock block, CategoryLabelPosition position, Graphics2D g2) {

    RectangleInsets insets = getTickLabelInsets();
    Size2D size = block.calculateDimensions(g2);
    Rectangle2D box = new Rectangle2D.Double(0.0, 0.0, size.getWidth(), size.getHeight());
    Shape rotatedBox = ShapeUtilities.rotateShape(box, position.getAngle(), 0.0f, 0.0f);
    double h = rotatedBox.getBounds2D().getHeight() + insets.getTop() + insets.getBottom();
    return h;
  }
Beispiel #10
0
    /**
     * sets the shape to paint
     *
     * @param shape a shape
     */
    public void setShape(Shape shape) {

      this.shape = shape;
      clips.clear();

      if (shape != null) {

        clips.add(shape.getBounds2D());
      }
    }
 public void selectAllWithin(BaseObject boundary) {
   BaseObject[] list = list();
   for (int i = 0; i < list.length; i++) {
     java.awt.Shape s1 = boundary.getShape();
     java.awt.Shape s2 = list[i].getShape();
     if (s1.contains(s2.getBounds2D())) {
       grab(list[i]);
     }
   }
 }
Beispiel #12
0
  /**
   * Returns the vertex, if any, whose shape contains (x, y). If (x,y) is contained in more than one
   * vertex's shape, returns the vertex whose center is closest to the pick point.
   *
   * @param layout the layout instance that records the positions for all vertices
   * @param x the x coordinate of the pick point
   * @param y the y coordinate of the pick point
   * @return the vertex whose shape contains (x,y), and whose center is closest to the pick point
   */
  public V getVertex(Layout<V, E> layout, double x, double y) {

    V closest = null;
    double minDistance = Double.MAX_VALUE;
    Point2D ip =
        vv.getRenderContext()
            .getMultiLayerTransformer()
            .inverseTransform(Layer.VIEW, new Point2D.Double(x, y));
    x = ip.getX();
    y = ip.getY();

    while (true) {
      try {
        for (V v : getFilteredVertices(layout)) {

          Shape shape = vv.getRenderContext().getVertexShapeTransformer().apply(v);
          // get the vertex location
          Point2D p = layout.apply(v);
          if (p == null) continue;
          // transform the vertex location to screen coords
          p = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, p);

          double ox = x - p.getX();
          double oy = y - p.getY();

          if (shape.contains(ox, oy)) {

            if (style == Style.LOWEST) {
              // return the first match
              return v;
            } else if (style == Style.HIGHEST) {
              // will return the last match
              closest = v;
            } else {

              // return the vertex closest to the
              // center of a vertex shape
              Rectangle2D bounds = shape.getBounds2D();
              double dx = bounds.getCenterX() - ox;
              double dy = bounds.getCenterY() - oy;
              double dist = dx * dx + dy * dy;
              if (dist < minDistance) {
                minDistance = dist;
                closest = v;
              }
            }
          }
        }
        break;
      } catch (ConcurrentModificationException cme) {
      }
    }
    return closest;
  }
Beispiel #13
0
  /**
   * Retrieves the shape template for <code>e</code> and transforms it according to the positions of
   * its endpoints in <code>layout</code>.
   *
   * @param layout the <code>Layout</code> which specifies <code>e</code>'s endpoints' positions
   * @param e the edge whose shape is to be returned
   * @return the transformed shape
   */
  private Shape getTransformedEdgeShape(Layout<V, E> layout, E e) {
    Pair<V> pair = layout.getGraph().getEndpoints(e);
    V v1 = pair.getFirst();
    V v2 = pair.getSecond();
    boolean isLoop = v1.equals(v2);
    Point2D p1 =
        vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, layout.apply(v1));
    Point2D p2 =
        vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, layout.apply(v2));
    if (p1 == null || p2 == null) return null;
    float x1 = (float) p1.getX();
    float y1 = (float) p1.getY();
    float x2 = (float) p2.getX();
    float y2 = (float) p2.getY();

    // translate the edge to the starting vertex
    AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1);

    Shape edgeShape = vv.getRenderContext().getEdgeShapeTransformer().apply(e);
    if (isLoop) {
      // make the loops proportional to the size of the vertex
      Shape s2 = vv.getRenderContext().getVertexShapeTransformer().apply(v2);
      Rectangle2D s2Bounds = s2.getBounds2D();
      xform.scale(s2Bounds.getWidth(), s2Bounds.getHeight());
      // move the loop so that the nadir is centered in the vertex
      xform.translate(0, -edgeShape.getBounds2D().getHeight() / 2);
    } else {
      float dx = x2 - x1;
      float dy = y2 - y1;
      // rotate the edge to the angle between the vertices
      double theta = Math.atan2(dy, dx);
      xform.rotate(theta);
      // stretch the edge to span the distance between the vertices
      float dist = (float) Math.sqrt(dx * dx + dy * dy);
      xform.scale(dist, 1.0f);
    }

    // transform the edge to its location and dimensions
    edgeShape = xform.createTransformedShape(edgeShape);
    return edgeShape;
  }
Beispiel #14
0
 public static Shape generatePolygon(
     int sides, int outsideRadius, int insideRadius, boolean normalize) {
   Shape shape = generatePolygon(sides, outsideRadius, insideRadius);
   if (normalize) {
     Rectangle2D bounds = shape.getBounds2D();
     GeneralPath path = new GeneralPath(shape);
     shape =
         path.createTransformedShape(
             AffineTransform.getTranslateInstance(-bounds.getX(), -bounds.getY()));
   }
   return shape;
 }
Beispiel #15
0
  private void calculateShape() {
    float t = 360 / blades;
    float a = angle;
    a = a > 360 ? a - 360 : a;
    fan = new Area();
    for (int i = 0; i < blades; i++) {
      Shape b = new Area(blade);
      Rectangle2D bounds = b.getBounds2D();
      b =
          AffineTransform.getTranslateInstance(
                  cx - bounds.getX() - bounds.getWidth() / 2, cy - bounds.getY())
              .createTransformedShape(b);
      bounds = b.getBounds2D();
      float bcx = (float) ((bounds.getWidth() * bladeCx) + bounds.getX());
      b = ShapeUtils.rotate(b, a, bcx, cy);
      ((Area) fan).add(new Area(b));

      a += t;
      a = a > 360 ? a - 360 : a;
    }
  }
Beispiel #16
0
  // Designed to be used by subclasses
  protected final Rectangle2D computeNewBoundsAfterMoving(Dimension space) {
    Rectangle2D bounds = shape.getBounds2D();

    if (bounds.getX() < 0 || bounds.getX() > space.getWidth()) dx = -dx;

    if (bounds.getY() < 0 || bounds.getY() > space.getHeight()) dy = -dy;

    Rectangle2D newBounds =
        new Rectangle2D.Double(
            bounds.getX() + dx, bounds.getY() + dy, bounds.getWidth(), bounds.getHeight());
    return newBounds;
  }
Beispiel #17
0
  @Override
  public CanvasPainter showTranslateAction(
      SVGHandle handle, Set<Element> elementSet, Point2D firstPoint, Point2D currentPoint) {

    CanvasPainter canvasPainter = null;

    // getting the element that will undergo the action
    Element element = elementSet.iterator().next();

    // getting the initial line
    Shape shape = getTransformedShape(handle, element, true);

    if (shape != null) {

      Point2D translationCoefficients =
          new Point2D.Double(
              currentPoint.getX() - firstPoint.getX(), currentPoint.getY() - firstPoint.getY());

      AffineTransform transform =
          AffineTransform.getTranslateInstance(
              translationCoefficients.getX(), translationCoefficients.getY());

      // computing the screen scaled shape
      final Shape fshape = handle.getTransformsManager().getScaledShape(shape, false, transform);

      // creating the set of the clips
      final Set<Rectangle2D> fclips = new HashSet<Rectangle2D>();
      fclips.add(fshape.getBounds2D());

      canvasPainter =
          new CanvasPainter() {

            @Override
            public void paintToBeDone(Graphics2D g) {

              g = (Graphics2D) g.create();
              g.setRenderingHint(
                  RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
              g.setColor(strokeColor);
              g.draw(fshape);
              g.dispose();
            }

            @Override
            public Set<Rectangle2D> getClip() {

              return fclips;
            }
          };
    }

    return canvasPainter;
  }
  public void fill(Shape s) {
    if (comp == null || comp instanceof AlphaComposite) super.fill(s);
    else {
      createBuffer();

      Graphics2D g2d = (Graphics2D) buffer.getGraphics();
      g2d.setPaint(this.getPaint());
      g2d.setColor(this.getColor());
      g2d.fill(s);

      drawComposite(s.getBounds2D(), null);
    }
  }
 // look through all drawn lables
 public boolean intersectsAny(Shape candidateShape) {
   boolean intersects = false;
   LabelDef labelDef = null;
   Rectangle2D currentBounds = candidateShape.getBounds2D();
   Iterator LabelDefIter = this.iterator();
   while ((LabelDefIter.hasNext()) && (!intersects)) {
     labelDef = (LabelDef) LabelDefIter.next();
     if (labelDef.isDrawn()) {
       intersects = labelDef.getBounds().intersects(currentBounds);
     }
   }
   return intersects;
 }
Beispiel #20
0
  public void draw(ColorMapper colorMapper, Graphics2D g2d) {

    g2d.setStroke(new BasicStroke(thickness));

    final double startX = Math.max(armsLenght, legsX) - headDiam / 2.0 + thickness;

    final Shape head = new Ellipse2D.Double(startX, thickness, headDiam, headDiam);
    final Rectangle2D headBound = head.getBounds2D();

    final double centerX = headBound.getCenterX();

    final Shape body =
        new Line2D.Double(centerX, headBound.getMaxY(), centerX, headBound.getMaxY() + bodyLenght);

    final Shape arms =
        new Line2D.Double(
            centerX - armsLenght,
            headBound.getMaxY() + armsY,
            centerX + armsLenght,
            headBound.getMaxY() + armsY);

    final double y = body.getBounds2D().getMaxY();

    final Shape legs1 = new Line2D.Double(centerX, y, centerX - legsX, y + legsY);
    final Shape legs2 = new Line2D.Double(centerX, y, centerX + legsX, y + legsY);

    g2d.setColor(colorMapper.getMappedColor(backgroundColor));
    g2d.fill(head);

    g2d.setColor(colorMapper.getMappedColor(foregroundColor));
    g2d.draw(head);
    g2d.draw(body);
    g2d.draw(arms);
    g2d.draw(legs1);
    g2d.draw(legs2);

    g2d.setStroke(new BasicStroke());
    throw new UnsupportedOperationException();
  }
 private Paint decodeGradient5(Shape s) {
   Rectangle2D bounds = s.getBounds2D();
   float x = (float) bounds.getX();
   float y = (float) bounds.getY();
   float w = (float) bounds.getWidth();
   float h = (float) bounds.getHeight();
   return decodeGradient(
       (0.5f * w) + x,
       (0.0f * h) + y,
       (0.5f * w) + x,
       (1.0f * h) + y,
       new float[] {0.1f, 0.49999997f, 0.9f},
       new Color[] {color7, decodeColor(color7, color8, 0.5f), color8});
 }
Beispiel #22
0
 public void paint(Graphics g, Shape a) {
   Graphics2D g2 = (Graphics2D) g;
   Rectangle2D abounds = a.getBounds2D();
   AffineTransform saveTransform = g2.getTransform();
   Paint savePaint = g2.getPaint();
   try {
     g2.translate(abounds.getX() - bounds.getX(), abounds.getY() - bounds.getY());
     g2.setPaint(Color.BLACK); // FIXME
     p.paint(g2);
   } finally {
     g2.setTransform(saveTransform);
     g2.setPaint(savePaint);
   }
 }
 private Paint decodeGradient3(Shape s) {
   Rectangle2D bounds = s.getBounds2D();
   float x = (float) bounds.getX();
   float y = (float) bounds.getY();
   float w = (float) bounds.getWidth();
   float h = (float) bounds.getHeight();
   return decodeGradient(
       (0.5f * w) + x,
       (0.0f * h) + y,
       (0.5f * w) + x,
       (1.0f * h) + y,
       new float[] {0.0f, 0.49573863f, 0.99147725f},
       new Color[] {color8, decodeColor(color8, color9, 0.5f), color9});
 }
 private Paint decodeGradient4(Shape s) {
   Rectangle2D bounds = s.getBounds2D();
   float x = (float) bounds.getX();
   float y = (float) bounds.getY();
   float w = (float) bounds.getWidth();
   float h = (float) bounds.getHeight();
   return decodeGradient(
       (0.5f * w) + x,
       (0.0f * h) + y,
       (0.5f * w) + x,
       (1.0f * h) + y,
       new float[] {0.0f, 0.1684492f, 1.0f},
       new Color[] {color10, decodeColor(color10, color11, 0.5f), color11});
 }
 private Paint decodeGradient13(Shape s) {
   Rectangle2D bounds = s.getBounds2D();
   float x = (float) bounds.getX();
   float y = (float) bounds.getY();
   float w = (float) bounds.getWidth();
   float h = (float) bounds.getHeight();
   return decodeGradient(
       (0.5f * w) + x,
       (0.0f * h) + y,
       (0.5f * w) + x,
       (1.0f * h) + y,
       new float[] {0.26047903f, 0.6302395f, 1.0f},
       new Color[] {color62, decodeColor(color62, color63, 0.5f), color63});
 }
 private Paint decodeGradient2(Shape s) {
   Rectangle2D bounds = s.getBounds2D();
   float x = (float) bounds.getX();
   float y = (float) bounds.getY();
   float w = (float) bounds.getWidth();
   float h = (float) bounds.getHeight();
   return decodeGradient(
       (0.25f * w) + x,
       (0.0f * h) + y,
       (0.25441176f * w) + x,
       (1.0016667f * h) + y,
       new float[] {0.0f, 0.5f, 1.0f},
       new Color[] {color3, decodeColor(color3, color2, 0.5f), color2});
 }
 private Paint decodeGradient10(Shape s) {
   Rectangle2D bounds = s.getBounds2D();
   float x = (float) bounds.getX();
   float y = (float) bounds.getY();
   float w = (float) bounds.getWidth();
   float h = (float) bounds.getHeight();
   return decodeGradient(
       (0.24868421f * w) + x,
       (0.0014705883f * h) + y,
       (0.24868421f * w) + x,
       (1.0f * h) + y,
       new float[] {0.0f, 0.5f, 1.0f},
       new Color[] {color48, decodeColor(color48, color49, 0.5f), color49});
 }
 private Paint decodeGradient9(Shape s) {
   Rectangle2D bounds = s.getBounds2D();
   float x = (float) bounds.getX();
   float y = (float) bounds.getY();
   float w = (float) bounds.getWidth();
   float h = (float) bounds.getHeight();
   return decodeGradient(
       (0.5f * w) + x,
       (0.0f * h) + y,
       (0.5f * w) + x,
       (1.0f * h) + y,
       new float[] {0.09f, 0.52f, 0.95f},
       new Color[] {color39, decodeColor(color39, color40, 0.5f), color40});
 }
  /**
   * Provides a mapping from the view coordinate space to the logical coordinate space of the model.
   *
   * @param v the view containing the view coordinates
   * @param x the X coordinate
   * @param y the Y coordinate
   * @param a the allocated region to render into
   * @param biasReturn either <code>Position.Bias.Forward</code> or <code>Position.Bias.Backward
   *     </code> is returned as the zero-th element of this array
   * @return the location within the model that best represents the given point of view
   * @see View#viewToModel
   */
  public int viewToModel(GlyphView v, float x, float y, Shape a, Position.Bias[] biasReturn) {

    Rectangle2D alloc = (a instanceof Rectangle2D) ? (Rectangle2D) a : a.getBounds2D();
    // Move the y co-ord of the hit onto the baseline.  This is because TextLayout supports
    // italic carets and we do not.
    TextHitInfo hit = layout.hitTestChar(x - (float) alloc.getX(), 0);
    int pos = hit.getInsertionIndex();

    if (pos == v.getEndOffset()) {
      pos--;
    }

    biasReturn[0] = hit.isLeadingEdge() ? Position.Bias.Forward : Position.Bias.Backward;
    return pos + v.getStartOffset();
  }
  public Shape modelToView(GlyphView v, int pos, Position.Bias bias, Shape a)
      throws BadLocationException {
    int offs = pos - v.getStartOffset();
    Rectangle2D alloc = a.getBounds2D();
    TextHitInfo hit =
        (bias == Position.Bias.Forward)
            ? TextHitInfo.afterOffset(offs)
            : TextHitInfo.beforeOffset(offs);
    float[] locs = layout.getCaretInfo(hit);

    // vertical at the baseline, should use slope and check if glyphs
    // are being rendered vertically.
    alloc.setRect(alloc.getX() + locs[0], alloc.getY(), 1, alloc.getHeight());
    return alloc;
  }