über Pfeile und Striche

takidoso

Erfahrenes Mitglied
Hallo und Halli,
ich habe einen "ArrowStroke" gebastelt, der mit einem Graphic2D.setStroke(...) gesetzt werden kann und dafür sorgt, dass z.B. Linien am Ende einen Pfeil erhalten.
Das funktioniert eigetnlich auch ganz gut, nur nun will ich die Möglichkeit geben, dass auch eine Pfeilspitze ohne Linie gezeichnet wird.
Dazu nahm ich eigentlich an dass ich die lineTos lediglich abhängig eines boolschen Wertes übergehen müsste, aber Pustekuchen :suspekt:
hier mal der ArrowStoke selbst (ich habe jetzt sogar die line'tos auskommentiert
Java:
import java.awt.BasicStroke;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;


public class ArrowStroke implements Stroke
{
	private Stroke  m_lineStroke = new BasicStroke();
	private double  m_headLength = 15;
	private double  m_headWidth  = 5;
	private double  m_barbValue  = 0;
	private boolean m_justHead   = false;
	
	public ArrowStroke()
	{
		m_lineStroke = new BasicStroke();
	}
	
	public ArrowStroke(Stroke lineStoke)
	{
		m_lineStroke = lineStoke;
	}
	
	public ArrowStroke(Stroke lineStroke, double headLength,double headWidth)
	{
		this(lineStroke);
		m_headWidth  = headWidth;
		m_headLength = headLength;
	}
	
	public ArrowStroke(Stroke lineStroke, double headLength,double headWidth, double barbValue, boolean justHead)
	{
		this(lineStroke, headLength, headWidth);
		m_barbValue = barbValue;
		m_justHead = justHead;
	}
	
	public ArrowStroke(Stroke lineStroke, double headLength,double headWidth, boolean justHead)
	{
		this(lineStroke, headLength, headWidth);		
		m_justHead = justHead;
	}
	
	public ArrowStroke(Stroke lineStroke, double headLength,double headWidth, double barbValue)
	{
		this(lineStroke, headLength, headWidth);
		m_barbValue = barbValue;
	}
	
	
	public ArrowStroke(double headLength, double headWidth)
	{
		this(new BasicStroke(), headLength, headWidth);
	}
	
	public ArrowStroke(double headLength,double headWidth, double barbValue, boolean justHead)
	{
		this(new BasicStroke(), headLength, headWidth, barbValue, justHead);
	}
	
	public ArrowStroke(double headLength,double headWidth, double barbValue)
	{
		this(new BasicStroke(), headLength, headWidth, barbValue);
	}
	
	public ArrowStroke(double headLength,double headWidth, boolean justHead)
	{
		this(new BasicStroke(), headLength, headWidth, justHead);
	}
	
	public void setHeadLength(double hL)
	{
		m_headLength = hL;
	}
	public double getHeadLength()
	{
		return m_headLength;
	}
	
	public void setHeadWidth(double hW)
	{
		m_headWidth = hW;
	}
	public double getHeadWidth()
	{
		return m_headWidth;
	}
	
	
	public Shape createStrokedShape(Shape shape)
	{
		// Start off by stroking the shape with a thin line. Store the
		// resulting shape in a GeneralPath object so we can add to it.
		GeneralPath strokedShape = new GeneralPath(m_lineStroke.createStrokedShape(shape));
		float[] coords = new float[6];
		float resentX = 0; 
		float resentY = 0;
		for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i.next())
		{
			int type = i.currentSegment(coords);
						
			switch (type)
			{
				case PathIterator.SEG_MOVETO :
					
					strokedShape.moveTo(coords[0], coords[1]);
					
					resentX = coords[0];
					resentY = coords[1];
					break;
				case PathIterator.SEG_LINETO :
					if (!m_justHead)
					{
						//strokedShape.lineTo(coords[0], coords[1]);
					}
					addArrowHead(resentX,resentY,coords[0], coords[1],strokedShape);					
					resentX = coords[0];
					resentY = coords[1];
					break;
				case PathIterator.SEG_QUADTO :
					if (!m_justHead)
					{
						//strokedShape.quadTo(coords[0], coords[1], coords[2], coords[3]);
					}
					
					addArrowHead(coords[0], coords[1], coords[2], coords[3], strokedShape);
					break;
				case PathIterator.SEG_CUBICTO :
					if (!m_justHead)
					{
						//strokedShape.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
					}
					addArrowHead(coords[2], coords[3], coords[4], coords[5], strokedShape);
					break;
				case PathIterator.SEG_CLOSE :
					strokedShape.closePath();
					break;
			}
		}

		return strokedShape;
	}
	
	private void addArrowHead(float x0, float y0, float x1, float y1, GeneralPath gPath)
	{
		gPath.append(calcArrowHead(x0,y0,x1,y1),false);
	}
	
	private Path2D.Double calcArrowHead(float x0, float y0, float x1, float y1)
	{
		Path2D.Double path;
		double dx = x1 - x0;
		double dy = y1 - y0;
		double lineLength = Math.sqrt(dx * dx + dy * dy);
		
		if (lineLength > m_headLength)
		{
			/*
			 *              R
			 *               |\
			 *               |  \
			 *   '0' -------P+----> '1'
			 *               |  /
			 *               |/
			 *              Q
			 *
			 */
			double ratio = m_headLength / lineLength;
			//double ratio
			double px = x1 - dx * ratio;
			double py = y1 - dy * ratio;
			
			
			double dxSq = dx * dx;
			double dySq = dy * dy;
			double headWidthSq = m_headWidth * m_headWidth;
			double wx = dy == 0 ? 0 : Math.signum(dy) * Math.sqrt(headWidthSq / ( 1 + ( dxSq / dySq ) ));
			double wy = dx == 0 ? 0 : Math.signum(dx) * Math.sqrt(headWidthSq / ( 1 + ( dySq / dxSq ) ));
			double qx = px - wx;
			double qy = py + wy;
			double rx = px + wx;
			double ry = py - wy;
			
			path = new Path2D.Double();
			//path.moveTo(x1, y1);
			//path.lineTo(qx, qy);
			//path.lineTo(rx, ry);
			path.moveTo(qx, qy);
			path.lineTo(x1, y1);
			path.lineTo(rx, ry);
			
			if (m_barbValue!=0)
			{
				ratio = (m_headLength/m_barbValue) / lineLength;
				double sx = x1 - dx * ratio;
				double sy = y1 - dy * ratio;
				path.lineTo(sx, sy);
			}
		}
		else
		{
			path = new Path2D.Double();
		}
		
		return path;
	}
	
}
und so kann er prinzipiell z.B. in einem JPanel verwendet werden
Java:
public void paintComponent(Graphics g)
{
  ....
   g.setStroke(new ArrowStroke(20,8,2,true));
   g.drawLine(10,  10,  50,  50);
}

malt leider noch den Strich mit obgleich die Klasse ArrowStroke dies selbst nicht mehr tun dürfte. Also nehme ich an wird dies woanders noch getan, aber nur wo?

Für hilfreiche Hinweise danke ich im Voraus,

Takidoso
 
Zurück