The Shape of a Stroke

P

Petra Neumann

Hi,

I would like to create a wiggly shape for the strokes I am drawing using
Graphics2D.
Basically instead of drawing general paths for each stroke I would like
to set the shape for each line.

For doing so I tried to apply a wiggly texture to the stroke.
However, I can't get this work. Because of the type of tiling that
TexturePaint does my lines sometimes end up in transparent space.

Are there any approaches for doing this? Could I, for example generate a
simple sinus curve and somehow set this for the shape of the stroke?
(similar to setting a dash-pattern).
Or is there a way to make textures work or something I haven't thought of?

Cheers,
Petra
 
A

Andrey Kuznetsov

I would like to create a wiggly shape for the strokes I am drawing using
Graphics2D.
Basically instead of drawing general paths for each stroke I would like
to set the shape for each line.

For doing so I tried to apply a wiggly texture to the stroke.
However, I can't get this work. Because of the type of tiling that
TexturePaint does my lines sometimes end up in transparent space.

Are there any approaches for doing this? Could I, for example generate a
simple sinus curve and somehow set this for the shape of the stroke?
(similar to setting a dash-pattern).
Or is there a way to make textures work or something I haven't thought of?

Petra,

don't really understood what you want.

Shape drawing is really simple thing:
just set your preferred Stroke and then call drawShape().

If you speak about Stroke which draws Shapes along another Shape,
then you should read Java 2D Graphics by Vincent J. Hardy and his Graphics
Layer Framework.
 
P

Petra Neumann

Shape drawing is really simple thing:
just set your preferred Stroke and then call drawShape().

yes, that is really easy if you want simple strokes, maybe with
different widths, or a dash-pattern. But, if you want a stroke with a
texture on it (that is not easily tileable) or sth. like a wiggly line
that's not that easy. Or to be exact, I don't know how to do it.
If you speak about Stroke which draws Shapes along another Shape,
then you should read Java 2D Graphics by Vincent J. Hardy and his Graphics
Layer Framework.
Ok, great. I will have a look at this reference.

Thanks,
Petra
 
F

fg

yes, that is really easy if you want simple strokes, maybe with different
widths, or a dash-pattern. But, if you want a stroke with a texture on it
(that is not easily tileable) or sth. like a wiggly line that's not that
easy. Or to be exact, I don't know how to do it.

Take a look at the method Graphics2D.setClip(Shape yourStroke)
And then, use Graphics2D.drawImage(Image yourTexture)


I hope this is the right answer, since my english is not the best ;-)

Fred.
 
A

Andrey Kuznetsov

Take a look at the method Graphics2D.setClip(Shape yourStroke)
And then, use Graphics2D.drawImage(Image yourTexture)

this is not what she needs,
may be the right way is to create transparent image,
draw appropriate Shape with right thikness and then use this image as mask
while painting texture image.
 
F

fg

this is not what she needs,
may be the right way is to create transparent image,
draw appropriate Shape with right thikness and then use this image as mask
while painting texture image.

Sorry, I'll try next time....
I misunderstood the word "Stroke", so I'll take a look into my favorite
translator for the next time ;-)

Fred.
 
J

Jim Sculley

Petra said:
yes, that is really easy if you want simple strokes, maybe with
different widths, or a dash-pattern. But, if you want a stroke with a
texture on it (that is not easily tileable) or sth. like a wiggly line
that's not that easy. Or to be exact, I don't know how to do it.

Draw a GeneralPath between the two endpoints, using a custom
PathIterator. The PathIterator describes the 'wiggly' aspect of the
line. The texture will do what it is supposed to do.

The key to making this simple is to understand how AffineTransform
works. By using an AffineTransform, you can treat every line as though
it starts at 0,0 and is horizontal. This greatly simplifies the math
needed to create the 'wiggles'.

The quickly thrown together example below draws a wiggly line between
two endpoints selected by mouse click. The line is filled via some
TexturePaint code copied from the Java Tutorial.

The heart of this example is the WigglePathIterator class. An instance
is created using two line end points, an amplitude and a period. The
line passed in is normalized via the AffineTransform, which allows the
next() method to compute segments as though the line being drawn is
horizontal with an end point at 0,0.

The 'y' coordinates repeat the following pattern:

1. Move from center up to 1/2 amplitude
2. Move down from 1/2 amplitude to center
3. Move down from center to -1/2 amplitude
4. Move up from -1/2 amplitude to center.

The 'x' coordinate simply indexes by 1/4 period for each segment.

When the x coordinate reaches the line length calculated in the
constructor, the isDone() method returns true.

The magic happens in the currentSegment() methods. The coordinate array
is first populated with the next position. Then the AffineTransform
(created in the constructor) is used to transform the coordinates in the
array back to the coordinate system of the original line.

Jim S.

===============================================
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.MouseInputAdapter;

public class WiggleTest {

public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new WigglePanel(10,50), BorderLayout.CENTER);
f.setSize(800,600);
f.setVisible(true);
}

private static class WigglePanel extends JPanel {
private Point lineStart;
private Point lineEnd;
private Point currentPoint;
private double amplitude;
private double period;

WigglePanel(double amplitude, double period) {
this.amplitude = amplitude;
this.period = period;
initConnections();
}

private void initConnections() {
MouseInputAdapter mia = new MouseInputAdapter() {
public void mouseClicked(MouseEvent me) {
if (lineEnd != null || lineStart == null) {
lineStart = me.getPoint();
lineEnd = null;
} else {
lineEnd = me.getPoint();
}
repaint();
}

public void mouseMoved(MouseEvent me) {
currentPoint = me.getPoint();
repaint();
}
};
addMouseListener(mia);
addMouseMotionListener(mia);
}

protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
/* Begin code copied from Java Tutorial */
BufferedImage bi = new BufferedImage(5, 5,
BufferedImage.TYPE_INT_RGB);
Graphics2D big = bi.createGraphics();
big.setColor(Color.blue);
big.fillRect(0, 0, 5, 5);
big.setColor(Color.lightGray);
big.fillOval(0, 0, 5, 5);
Rectangle r = new Rectangle(0,0,5,5);
g2d.setPaint(new TexturePaint(bi, r));
/* End code copied from Java Tutorial */
g2d.setStroke(new BasicStroke(5.0f));
if (lineStart != null && lineEnd != null) {
GeneralPath gp = new GeneralPath();
gp.moveTo((float)lineStart.getX(),

(float)lineStart.getY());
gp.append(new WigglePathIterator(
lineStart, lineEnd, amplitude, period), false);
g2d.draw(gp);
} else if (lineStart != null && currentPoint != null) {
g2d.draw(new Line2D.Double(lineStart, currentPoint));
}
}
}

private static class WigglePathIterator implements PathIterator {
double x0, x1, y0, y1;
double amplitude, period;
boolean rising;
Point2D currentSeg;
AffineTransform at;
double length = 0;

WigglePathIterator(
Point start,
Point end,
double amplitude,
double period) {
x0 = start.getX();
x1 = end.getX();
y0 = start.getY();
y1 = end.getY();
this.amplitude = amplitude;
this.period = period;
currentSeg = new Point2D.Double(0,0);
length = Math.sqrt(Math.pow(x1-x0,2) + Math.pow(y1-y0,2));
double angle = Math.atan((y1-y0)/(x1-x0));
//normalize the angle value for
//the (-x,-y) and (-x,+y) quadrants
if (x1 < x0) {
if (y1 > y0) {
angle = Math.PI + angle;
} else {
angle = angle - Math.PI;
}
}
at = AffineTransform.getTranslateInstance(x0,y0);
at.rotate(angle);
}

public int getWindingRule() {
return PathIterator.WIND_NON_ZERO;
}

public boolean isDone() {
return currentSeg.getX() > length;
}

public void next() {
Point2D oldSeg = currentSeg;
double nextX = 0;
double nextY = 0;
if (oldSeg.getY() != 0) {
nextY = 0;
} else if (rising) {
nextY = amplitude / 2;
rising = false;
} else {
nextY = -(amplitude / 2);
rising = true;
}
nextX = oldSeg.getX() + period / 4;
currentSeg.setLocation(nextX, nextY);
}

public int currentSegment(float[] coords) {
coords[0] = (float)currentSeg.getX();
coords[1] = (float)currentSeg.getY();
at.transform(coords,0,coords,0,1);
return SEG_LINETO;
}

public int currentSegment(double[] coords) {
coords[0] = currentSeg.getX();
coords[1] = currentSeg.getY();
at.transform(coords,0,coords,0,1);
return SEG_LINETO;
}
}
}

===============================================
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top