2014-02-06 4 views
0

Я пытаюсь нарисовать изогнутую стрелку линии на уложенной гистограмме. Я смог нарисовать кривую линию и стрелу. Но я не могу подключить стрелку к концу изогнутой линии. Я использую аффинное преобразование, чтобы нарисовать кривую линию. Нижняя ссылка описывает кривую линию и стрелку, которые я смог нарисовать http://i58.tinypic.com/2m422hy.png.Can. Кто-нибудь подскажет мне, как соединить стрелку до конца изогнутой линии.Рисование кривой кривой стрелка на гистограмме с использованием аффинного преобразования

Адрес

упаковка Stack;

/* * Чтобы изменить этот шаблон, выберите «Инструменты» | Шаблоны * и откройте шаблон в редакторе. */

/** * * @author OSPL-B4 / / * Для того, чтобы изменить этот шаблон, выберите Tools | Шаблоны * и откройте шаблон в редакторе. */

import java.awt.BasicStroke; 
import java.awt.Color; 
import java.awt.Font; 

import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Paint; 
import java.awt.Polygon; 
import java.awt.Shape; 
import java.awt.Stroke; 
import java.awt.font.TextLayout; 
import java.awt.geom.AffineTransform; 
import java.awt.geom.Ellipse2D; 
import java.awt.geom.Line2D; 
import java.awt.geom.Path2D; 
import java.awt.geom.Point2D; 
import java.awt.geom.QuadCurve2D; 
import java.awt.geom.Rectangle2D; 
import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.Serializable; 

import org.jfree.chart.annotations.CategoryAnnotation; 

import org.jfree.chart.axis.CategoryAnchor; 
import org.jfree.chart.axis.CategoryAxis; 
import org.jfree.chart.axis.ValueAxis; 
import org.jfree.chart.event.AnnotationChangeListener; 
import org.jfree.chart.plot.CategoryPlot; 
import org.jfree.chart.plot.Plot; 
import org.jfree.chart.plot.PlotOrientation; 
import org.jfree.data.category.CategoryDataset; 
import org.jfree.io.SerialUtilities; 
import org.jfree.ui.RectangleEdge; 
import org.jfree.util.ObjectUtilities; 
import org.jfree.util.PaintUtilities; 

// импорт java.awt.font;

/** 
* A line annotation that can be placed on a 
* {@link org.jfree.chart.plot.CategoryPlot}. 
*/ 
public class CategoryLineAnnotation_demo1 implements CategoryAnnotation, 
               Cloneable, Serializable { 

    /** The category for the start of the line. */ 
    private Comparable category1; 

    /** The value for the start of the line. */ 
    private double value1; 

    /** The category for the end of the line. */ 
    private Comparable category2; 

    /** The value for the end of the line. */ 
    private double value2; 
    private final int ARR_SIZE = 4; 
    /** The line color. */ 
    private transient Paint paint = Color.black; 

    /** The line stroke. */ 
    private transient Stroke stroke = new BasicStroke(1.0f); 

    /** 
    * Creates a new annotation that draws a line between (category1, value1) 
    * and (category2, value2). 
    * 
    * @param category1 the category (<code>null</code> not permitted). 
    * @param value1 the value. 
    * @param category2 the category (<code>null</code> not permitted). 
    * @param value2 the value. 
    */ 
    public CategoryLineAnnotation_demo1(Comparable category1, double value1, 
            Comparable category2, double value2, 
            Paint paint, Stroke stroke) { 
     if (category1 == null) { 
      throw new IllegalArgumentException("Null 'category1' argument."); 
     } 
     if (category2 == null) { 
      throw new IllegalArgumentException("Null 'category2' argument."); 
     } 
     if (paint == null) { 
      throw new IllegalArgumentException("Null 'paint' argument."); 
     } 
     if (stroke == null) { 
      throw new IllegalArgumentException("Null 'stroke' argument."); 
     } 
     this.category1 = category1; 

     System.out.println("First Category value is "+category1); 
     this.value1 = value1; 
     this.category2 = category2; 

     System.out.println("Second Category value is "+category2); 
     this.value2 = value2; 
     this.paint = paint; 
     this.stroke = stroke; 
    } 


    /** 
    * Returns the category for the start of the line. 
    * 
    * @return The category for the start of the line (never <code>null</code>). 
    */ 
    public Comparable getCategory1() { 
     return this.category1; 
    } 

    /** 
    * Sets the category for the start of the line. 
    * 
    * @param category the category (<code>null</code> not permitted). 
    */ 
    public void setCategory1(Comparable category) { 
     if (category == null) { 
      throw new IllegalArgumentException("Null 'category' argument."); 
     } 
     this.category1 = category; 
    } 

    /** 
    * Returns the y-value for the start of the line. 
    * 
    * @return The y-value for the start of the line. 
    */ 
    public double getValue1() { 
     return this.value1; 
    } 

    /** 
    * Sets the y-value for the start of the line. 
    * 
    * @param value the value. 
    */ 
    public void setValue1(double value) { 
     this.value1 = value; 
    } 

    /** 
    * Returns the category for the end of the line. 
    * 
    * @return The category for the end of the line (never <code>null</code>). 
    */ 
    public Comparable getCategory2() { 
     return this.category2; 
    } 

    /** 
    * Sets the category for the end of the line. 
    * 
    * @param category the category (<code>null</code> not permitted). 
    */ 
    public void setCategory2(Comparable category) { 
     if (category == null) { 
      throw new IllegalArgumentException("Null 'category' argument."); 
     } 
     this.category2 = category; 
    } 

    /** 
    * Returns the y-value for the end of the line. 
    * 
    * @return The y-value for the end of the line. 
    */ 
    public double getValue2() { 
     return this.value2; 
    } 

    /** 
    * Sets the y-value for the end of the line. 
    * 
    * @param value the value. 
    */ 
    public void setValue2(double value) { 
     this.value2 = value; 
    } 

    /** 
    * Returns the paint used to draw the connecting line. 
    * 
    * @return The paint (never <code>null</code>). 
    */ 
    public Paint getPaint() { 
     return this.paint; 
    } 

    /** 
    * Sets the paint used to draw the connecting line. 
    * 
    * @param paint the paint (<code>null</code> not permitted). 
    */ 
    public void setPaint(Paint paint) { 
     if (paint == null) { 
      throw new IllegalArgumentException("Null 'paint' argument."); 
     } 
     this.paint = paint; 
    } 

    /** 
    * Returns the stroke used to draw the connecting line. 
    * 
    * @return The stroke (never <code>null</code>). 
    */ 
    public Stroke getStroke() { 

     // System.out.println("In Stacked bar Stroke is "+getStroke()); 
     return this.stroke; 
    } 

    /** 
    * Sets the stroke used to draw the connecting line. 
    * 
    * @param stroke the stroke (<code>null</code> not permitted). 
    */ 
    public void setStroke(Stroke stroke) { 
     if (stroke == null) { 
      throw new IllegalArgumentException("Null 'stroke' argument."); 
     } 
     this.stroke = stroke; 
    } 

    /** 
    * Draws the annotation. 
    * 
    * @param g2 the graphics device. 
    * @param plot the plot. 
    * @param dataArea the data area. 
    * @param domainAxis the domain axis. 
    * @param rangeAxis the range axis. 
    */ 
    public void draw(Graphics2D g2, CategoryPlot plot, Rectangle2D dataArea, 
        CategoryAxis domainAxis, ValueAxis rangeAxis) { 

     CategoryDataset dataset = plot.getDataset(); 
     int catIndex1 = dataset.getColumnIndex(this.category1); 
     int catIndex2 = dataset.getColumnIndex(this.category2); 

     int catCount = dataset.getColumnCount(); 

     double lineX1 = 0.0f; 
     double lineY1 = 0.0f; 
     double lineX2 = 0.0f; 
     double lineY2 = 0.0f; 
     PlotOrientation orientation = plot.getOrientation(); 
     RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
      plot.getDomainAxisLocation(), orientation); 
     RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
      plot.getRangeAxisLocation(), orientation); 

     if (orientation == PlotOrientation.HORIZONTAL) { 
      lineY1 = domainAxis.getCategoryJava2DCoordinate(
       CategoryAnchor.MIDDLE, catIndex1, catCount, dataArea, 
       domainEdge); 
      lineX1 = rangeAxis.valueToJava2D(this.value1, dataArea, rangeEdge); 
      lineY2 = domainAxis.getCategoryJava2DCoordinate(
       CategoryAnchor.MIDDLE, catIndex2, catCount, dataArea, 
       domainEdge); 
      lineX2 = rangeAxis.valueToJava2D(this.value2, dataArea, rangeEdge); 
     } 
     else if (orientation == PlotOrientation.VERTICAL) { 
      lineX1 = domainAxis.getCategoryJava2DCoordinate(
       CategoryAnchor.MIDDLE, catIndex1, catCount, dataArea, 
       domainEdge); 
      lineY1 = rangeAxis.valueToJava2D(this.value1, dataArea, rangeEdge); 
      lineX2 = domainAxis.getCategoryJava2DCoordinate(
       CategoryAnchor.MIDDLE, catIndex2, catCount, dataArea, 
       domainEdge); 
      lineY2 = rangeAxis.valueToJava2D(this.value2, dataArea, rangeEdge); 
     } 
     g2.setPaint(this.paint); 
     g2.setStroke(this.stroke); 

     drawArrow(g2,(int) lineX1, (int) lineY1, (int) lineX2, (int) lineY2); 
    } 

    void drawArrow(Graphics g1, int x1, int y1, int x2, int y2) { 
      Graphics2D g = (Graphics2D) g1.create(); 


      double dx = x2 - x1, dy = y2 - y1; 

      System.out.println("Value of DX "+dx); 
      System.out.println("Value of DY "+dy); 
      double angle = Math.atan2(dy, dx); 

      System.out.println("Getting angle "+angle); 
      int len = (int) Math.sqrt(dx*dx + dy*dy); 
      AffineTransform at = AffineTransform.getTranslateInstance(x1, y1); 
      at.concatenate(AffineTransform.getRotateInstance(angle)); 
      g.transform(at); 

      System.out.println("Affine transform X co-ordinate value is "+at.getScaleX()); 

      System.out.println("Affine transform Y co-ordinate value is "+at.getScaleY()); 
     float center1=(x1+x2)/2-40; 
     float center2= (y1+y2)/2-40;  
     QuadCurve2D q=new QuadCurve2D.Float(0,0,center1,center2,x2,y2); 


     g.draw(q); 

     g.setColor(Color.RED); 

     System.out.println("Length of arrow is "+len); 

     System.out.println("Get Start point 2D "+q.getP1()); 
     System.out.println("Get End point 2D "+q.getP2()); 

      g.fillPolygon(new int[] {len, len-ARR_SIZE, len-ARR_SIZE-10, len-60}, 
         new int[] {0, -ARR_SIZE, ARR_SIZE-20, 5}, 4); 


     } 

     public void paintComponent(Graphics g) { 
      for (int x = 15; x < 200; x += 16) 
       drawArrow(g, x, x, x, 150); 
      drawArrow(g, 30, 300, 300, 190); 
     } 



    /** 
    * Tests this object for equality with another. 
    * 
    * @param obj the object (<code>null</code> permitted). 
    * 
    * @return <code>true</code> or <code>false</code>. 
    */ 
    public boolean equals(Object obj) { 
     if (obj == this) { 
      return true; 
     } 
     if (!(obj instanceof CategoryLineAnnotation_demo1)) { 
      return false; 
     } 
     CategoryLineAnnotation_demo1 that = (CategoryLineAnnotation_demo1) obj; 
     if (!this.category1.equals(that.getCategory1())) { 
      return false; 
     } 
     if (this.value1 != that.getValue1()) { 
      return false; 
     } 
     if (!this.category2.equals(that.getCategory2())) { 
      return false; 
     } 
     if (this.value2 != that.getValue2()) { 
      return false; 
     } 
     if (!PaintUtilities.equal(this.paint, that.paint)) { 
      return false; 
     } 
     if (!ObjectUtilities.equal(this.stroke, that.stroke)) { 
      return false; 
     } 
     return true; 
    } 

    /** 
    * Returns a hash code for this instance. 
    * 
    * @return A hash code. 
    */ 
    public int hashCode() { 
     // TODO: this needs work 
     return this.category1.hashCode() + this.category2.hashCode(); 
    } 

    /** 
    * Returns a clone of the annotation. 
    * 
    * @return A clone. 
    * 
    * @throws CloneNotSupportedException this class will not throw this 
    *   exception, but subclasses (if any) might. 
    */ 
    public Object clone() throws CloneNotSupportedException { 
     return super.clone(); 
    } 

    /** 
    * Provides serialization support. 
    * 
    * @param stream the output stream. 
    * 
    * @throws IOException if there is an I/O error. 
    */ 
    private void writeObject(ObjectOutputStream stream) throws IOException { 
     stream.defaultWriteObject(); 
     SerialUtilities.writePaint(this.paint, stream); 
     SerialUtilities.writeStroke(this.stroke, stream); 
    } 

    /** 
    * Provides serialization support. 
    * 
    * @param stream the input stream. 
    * 
    * @throws IOException if there is an I/O error. 
    * @throws ClassNotFoundException if there is a classpath problem. 
    */ 
    private void readObject(ObjectInputStream stream) 
     throws IOException, ClassNotFoundException { 
     stream.defaultReadObject(); 
     this.paint = SerialUtilities.readPaint(stream); 
     this.stroke = SerialUtilities.readStroke(stream); 
    } 

@Override 
public void addChangeListener(AnnotationChangeListener al) { 

} 

@Override 
public void removeChangeListener(AnnotationChangeListener al) { 


} 

} 

ответ

1

Вы можете создать голову стрелки на основе последнего сегмента линии (которые, возможно, уже преобразованный с помощью AffineTransform)

import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Point; 
import java.awt.Shape; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionListener; 
import java.awt.geom.Line2D; 
import java.awt.geom.Path2D; 
import java.awt.geom.Point2D; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class ArrowPainter 
{ 
    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       createAndShowGUI(); 
      } 
     }); 
    } 

    private static void createAndShowGUI() 
    { 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JPanel panel = new ArrowPaintPanel(); 
     f.getContentPane().add(panel); 
     f.setSize(500,500); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 
} 

class ArrowPaintPanel extends JPanel implements MouseMotionListener 
{ 
    private Point2D startPoint = null; 
    private Point2D endPoint = null; 

    ArrowPaintPanel() 
    { 
     addMouseMotionListener(this); 
    } 

    @Override 
    protected void paintComponent(Graphics gr) 
    { 
     super.paintComponent(gr); 
     Graphics2D g = (Graphics2D)gr; 

     if (startPoint == null) 
     { 
      startPoint = new Point(getWidth()/2, getHeight()/2); 
     } 
     if (endPoint == null) 
     { 
      return; 
     } 

     Line2D line = new Line2D.Double(startPoint, endPoint); 
     Shape arrowHead = createArrowHead(line, 30, 20); 
     g.draw(line); 
     g.fill(arrowHead); 
    } 

    @Override 
    public void mouseDragged(MouseEvent e) 
    { 
     endPoint = e.getPoint(); 
     repaint(); 
    } 

    @Override 
    public void mouseMoved(MouseEvent e) 
    { 
     endPoint = e.getPoint(); 
     repaint(); 
    } 

    private static Shape createArrowHead(Line2D line, double length, double width) 
    { 
     Point2D p0 = line.getP1(); 
     Point2D p1 = line.getP2(); 
     double x0 = p0.getX(); 
     double y0 = p0.getY(); 
     double x1 = p1.getX(); 
     double y1 = p1.getY(); 
     double dx = x1 - x0; 
     double dy = y1 - y0; 
     double invLength = 1.0/Math.sqrt(dx*dx+dy*dy); 
     double dirX = dx * invLength; 
     double dirY = dy * invLength; 
     double ax = x1 - length * dirX; 
     double ay = y1 - length * dirY; 
     double offsetX = width * -dirY * 0.5; 
     double offsetY = width * dirX * 0.5; 
     double c0x = ax + offsetX; 
     double c0y = ay + offsetY; 
     double c1x = ax - offsetX; 
     double c1y = ay - offsetY; 
     Path2D arrowHead = new Path2D.Double(); 
     arrowHead.moveTo(x1, y1); 
     arrowHead.lineTo(c0x, c0y); 
     arrowHead.lineTo(c1x, c1y); 
     arrowHead.closePath(); 
     return arrowHead; 
    } 


} 

EDIT: Обновление для выше EDIT и комментарии: Это очень много кода, но все же ничего, что можно легко проверить. Что происходит, когда вы заменить вашу линию

drawArrow(g2,(int) lineX1, (int) lineY1, (int) lineX2, (int) lineY2); 

с

g.fill(createArrowHead(new Line2D.Double(lineX1, lineY1, lineX2, lineY2), 30, 20)); 

?

+0

Я могу нарисовать стрелу на прямой линии. Я хочу нарисовать arraw для изогнутой линии. Можете ли вы помочь мне в этом. – user3209213

+0

Возможно, вы должны добавить код (то есть, где вы создаете и нарисовать криволинейную строку) в свой исходный вопрос – Marco13

+0

-Я вставил код в исходный вопрос. Можете ли вы указать, как я могу вращать стрелку, чтобы она соответствует изогнутой линии, я имею в виду, что она соединена с изогнутой линией. – user3209213

Смежные вопросы