SegmentIndexStyle.java

/*
 * Copyright (c) 2016 Vivid Solutions.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
 * and the Eclipse Distribution License is available at
 *
 * http://www.eclipse.org/org/documents/edl-v10.php.
 */

package org.locationtech.jtstest.testbuilder.ui.style;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;

import org.locationtech.jts.awt.FontGlyphReader;
import org.locationtech.jts.geom.Quadrant;
import org.locationtech.jtstest.testbuilder.ui.Viewport;


public class SegmentIndexStyle 
  extends SegmentStyle
{
  private final static double MIN_LEN = 10;
  private final static int CHAR_WIDTH_APPROX = 6;
  private final static int CHAR_HEIGHT_APPROX = 6;
  private final static int VERTEX_OFFSET = 15;
  private final static int BOX_PAD = 1;
  private final static Font FONT = new Font(FontGlyphReader.FONT_SANSSERIF, Font.PLAIN, 10);
  private static final int MIN_LABEL_DIST = 300;
  
  private Color color = Color.RED;

  private double lastX = 0;
  private double lastY = 0;
  
  public SegmentIndexStyle(Color color) {
    this.color = color;
  }

  protected void paint(int index, Point2D p0, Point2D p1, int lineType, Viewport vp, Graphics2D gr)
  throws Exception
  {
    double len = p0.distance(p1);
    // don't try and label very short segments
    // can't compute label location for zero-length segments
    if (len < MIN_LEN) {
      return;
    }
    
    double vertexOffset = len / 4;
    if (vertexOffset > VERTEX_OFFSET)
      vertexOffset = VERTEX_OFFSET;
    
    double dx = p1.getX() - p0.getX();
    double dy = p1.getY() - p0.getY();
    int quadrant = Quadrant.quadrant(dx, -dy);
    
    String indexStr = Integer.toString(index);
    double boxMaxX = /*2 * BOX_PAD +*/ indexStr.length() * CHAR_WIDTH_APPROX;
    double boxMaxY = 2 * BOX_PAD + CHAR_HEIGHT_APPROX;
    
    double strOffsetX = BOX_PAD;
    double strOffsetY = -BOX_PAD;
    switch (quadrant) {
    case 0:
      strOffsetX = -boxMaxX;
      break;
    case 1:
      break;
    case 2:
      strOffsetY = boxMaxY;
      break;
    case 3:
      strOffsetX = -boxMaxX;
      strOffsetY = boxMaxY;
      break;
    }
    
    double x = p0.getX() + dx/len*vertexOffset + strOffsetX;
    double y = p0.getY() + dy/len*vertexOffset + strOffsetY;
    
    // cache last point drawn for simple label deconfliction
    boolean doDraw = index == 0 || distToLast(x, y) > MIN_LABEL_DIST; 
    
    if (doDraw) {
      gr.setColor(color);
      gr.setFont(FONT);
      gr.drawString(indexStr, (int) x, (int) y);
      
      lastX = x;
      lastY = y;
    }
  }

  private double distToLast(double x, double y) {
    return (x - lastX)*(x - lastX) + (y - lastY)*(y - lastY);
  }
  


}