Java - drawing an arrow between two objects with static dimensions - java

i'm stuck on following problem;
I have a rectangle (50x40 px lets say, position : x1,y1) and a cirle (radius 30, positin x2,y2). Now I want to draw an arrow between them
void drawArrow(Graphics g1, int x1, int y1, int x2, int y2,) {
//x1 and y1 are coordinates of circle or rectangle
//x2 and y2 are coordinates of circle or rectangle, to this point is directed the arrow
Graphics2D g = (Graphics2D) g1.create();
double dx=x2-x1;
double dy=y2-y1;
double angle = Math.atan2(dy, dx);
int len = (int) Math.sqrt(dx*dx + dy*dy);
AffineTransform at = AffineTransform.getTranslateInstance(x1, y1);
at.concatenate(AffineTransform.getRotateInstance(angle));
g.transform(at);
g.drawLine(0,0,len,0);
g.fillPolygon(new int[] {len, len-ARR_SIZE, len-ARR_SIZE, len},
new int[] {0, -ARR_SIZE, ARR_SIZE, 0}, 4);
}
This Code obviously connects only the specific points of rect and circle ( on this picture i connected the points in the middle http://imageshack.us/photo/my-images/341/arrk.jpg/ ). Do you have any idea how to achieve stg like this? (http://imageshack.us/photo/my-images/833/arr2u.jpg/ ) ... my idea was to shorten the length and calculate the new coordinates, but i'm bit struggling with it.
// I call this function this way:
drawArrow(g,temp.x+radius/2,temp.y+radius/2,temp2.x+width/2,temp2.y+height/2);

Easiest way is to set the clipping. If you add your circle and your rect to the clipping, it won't draw on it.
It doesn't solve the problem or drawing the arrow though. To solve this problem, you need to use Shape.getBounds(), figure out the bounds for the rectangle, then calculate the angle to your circle and use trigonometry to find the right spot on the rectangle

Related

What it's wrong in translation function?

I tried to create and translate a polygon in openGL, I create a function for translation but this create a white line from x0 to v_size and I don't understand why ?
This is my function for polygon translation
public void translate1(GL2 gl, double x0, double x1, double y0, double y1){
double step = 0.2;
for(double i = 0; i < v_size; i += step){
gl.glBegin(GL2.GL_POLYGON);
gl.glVertex2d(x0 + i, y0);
gl.glVertex2d(x0 + i, y1);
gl.glVertex2d(x1 + i, y1);
gl.glVertex2d(x1 + i, y0);
gl.glEnd();
}
}
Initial x0 = 0, x1 = 10, y0 = 20, y1 = 30.
Thanks !
Have a nice day!
The reason for this is, that you draw squares every step units away from each other. Since nothing gets cleared in the meantime, the overlapping quads form a line.
It is rather unclear what you are trying to achieve. A translation would usually not draw multiple quads. If you are trying to do an animation, then you'll have to split the movement over multiple frames and draw exactly one square in every frame.

Polylines outline construction / Drawing thick polylines

I'm facing a task where I have to draw polylines using polygons.
As an input parameters I have an array of points and thickness value. See picture below.
I have points that form black polyline and thickness e.g. 10px. Now I need to calculate points and construct a blue polyline to form a polygon and then render it.
There are some articles related to this:
Drawing Polylines by Tessellation
An algorithm for polylines outline construction
EFFICIENT RENDERING OF THICK POLYLINES
But I find them a bit complicated and difficult to understand.
Aren't there any existing libraries or more simple algorithms to implement this. No rounded joints are required. I'm using java and libGDX.
The algorithm is as follows:
for each line:
find the parallel line upwards:
find the perpendicular: has a slope m2 in approximate
check which side is right (compare angles)
find the two points of the parallel line by solving a small equation problem (A, B, C)
if this line is the first one keep it (l1)
else find the intersection with the previous line (l1, l2): this will give the next articulation point
The yellow line is the one you want; the red line is the general parallel line.
The articulation points are in green. You can print this bufferedimage in some component.
Notes: the width of the polygon cannot be fixed as you realize because at articulation points the distance will be larger. What is guaranteed is that the distance between line segments is constant.
int[] approximate(int[] p, int[] p2, double dr, int l) { // l is the distance, dr is 0 for the beginning of the segment and 1 for the end
double d=Math.sqrt(Math.pow(p[0]-p2[0], 2)+Math.pow(p[1]-p2[1], 2));
double ix=p[0]+dr*(p2[0]-p[0]), iy=p[1]+dr*(p2[1]-p[1]);
double x1=0, x2=0, y1=0, y2=0;
if(p2[0]==p[0]) {
x1=ix+l; x2=ix-l; y1=iy; y2=iy;
}
else {
double m=1.0*(p2[1]-p[1])/(p2[0]-p[0]);
if(Math.abs(m)==0) {
x1=ix; x2=ix; y1=iy+l; y2=iy-l;
}
else {
double m2=-1/m;
double c=iy-m2*ix;
double A=1+m2*m2, B=-2*(ix-m2*c+m2*iy), C=ix*ix+iy*iy+c*c-2*c*iy-l*l;
x1=(-B+Math.sqrt(B*B-4*A*C))/(2*A); x2=(-B-Math.sqrt(B*B-4*A*C))/(2*A); y1=m2*x1+c; y2=m2*x2+c;
}
}
int[] cp1={p2[0]-p[0], p2[1]-p[1]}, cp2={(int)x1-p[0], (int)y1-p[1]}, xy=new int[2];
int cpp=compareAngles(cp1, cp2);
if(cpp>0) { xy[0]=(int)x1; xy[1]=(int)y1; } else { xy[0]=(int)x2; xy[1]=(int)y2; }
return xy;
}
void poly() {
int[][] p={{100, 400}, {110, 440}, {250, 300}, {350, 400}, {300, 310}};
BufferedImage bim=new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
Graphics2D g=(Graphics2D)bim.getGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, 500, 500);
g.setStroke(new BasicStroke(5f));
g.setColor(Color.black);
Line2D.Double l1=new Line2D.Double(), l2=new Line2D.Double();
int[] currentp=new int[2], lastp=new int[2];
for(int i=0; i<p.length-1; i++) {
g.setColor(Color.black);
g.drawLine(p[i][0], p[i][1], p[i+1][0], p[i+1][1]);
int[] p1=approximate(p[i], p[i+1], 0, 10), p2=approximate(p[i], p[i+1], 1, 10);
g.setColor(Color.red);
g.drawLine(p1[0], p1[1], p2[0], p2[1]);
if(i==0) { l1=new Line2D.Double(p1[0], p1[1], p2[0], p2[1]); currentp[0]=p1[0]; currentp[1]=p1[1]; }
else {
l2=new Line2D.Double(p1[0], p1[1], p2[0], p2[1]);
int[] pi=intersectionPoint(l1, l2);
g.setColor(Color.green);
g.fillOval(pi[0], pi[1], 5, 5);
g.setColor(Color.yellow);
g.drawLine(currentp[0], currentp[1], pi[0], pi[1]);
currentp[0]=pi[0]; currentp[1]=pi[1];
l1.setLine(l2);
}
if(i==p.length-2) { lastp[0]=p2[0]; lastp[1]=p2[1]; }
}
g.setColor(Color.yellow);
g.drawLine(currentp[0], currentp[1], lastp[0], lastp[1]);
}
public int[] intersectionPoint(Line2D.Double l1, Line2D.Double l2) {
return intersectionPoint((int)l1.getX1(), (int)l1.getY1(), (int)l1.getX2(), (int)l1.getY2(), (int)l2.getX1(), (int)l2.getY1(), (int)l2.getX2(), (int)l2.getY2());
}
public int[] intersectionPoint(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
int[] xy={(int)(1.0*((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4))),
(int)(1.0*((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)))};
return xy;
}
public int compareAngles(int[] a, int[] b) {
int cp=a[0]*b[1]-a[1]*b[0];
return -cp;
}
I'm not really sure why you want to implement some advanced graphics alghoritms in framework which first place duty is to render things easily :)
Libgdx has built-in ShapeRenderer that allows you to draw simple shapes. All you have to do is to calculate new vertices basing on thickness and pass them to the ShapeRenderer to draw circles and lines that connects these circles.
To make it super-easy you can even use
rectLine(float x1, float y1, float x2, float y2, float width)
method that allows you to draw line of given thickness. So only what you need to do is to iterate over points and draw all lines like in this pseudo code:
for point in points:
if thereIsANextPoint():
next = getNextPoint()
sr.rectLine(point.x, point.y, next.x, next .y, thickness)
The nice description of how to use ShapeRenderer is included in reference I've attached above
I guess that there can be a little problem with joinings between points (because of different angles for example) I think that rendering circles above this joins will be good workarround :)

Rotate a rect about an arc in java swing

I want to move this small rectangle about the circumference of the circle, so that I looks and moves like a canon.
Code
private void doDrawing(Graphics g){
g.setColor(Color.BLUE);
g.fillArc(-CANON_RADIUS/2, this.getHeight()-CANON_RADIUS/2, CANON_RADIUS, CANON_RADIUS, 0, 90);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
Rectangle rect = new Rectangle(CANON_RADIUS/2, this.getHeight()-CANON_RADIUS/2, CANON_WIDTH, CANON_HEIGHT);
AffineTransform transform = new AffineTransform();
transform.rotate(Math.toRadians(-60), rect.getX() + rect.width/2, rect.getY() + rect.height/2);
Shape transformed = transform.createTransformedShape(rect);
g2d.fill(transformed);
}
This code rotates rectangle about its centre. How can I rotate rectangle around the circumference?
First things first, you can use a transformation matrix for this, like you are already using:
http://en.wikipedia.org/wiki/Transformation_matrix
Edit:
looking at your code, you want to rotate your canon around an anchor. Please look at the javadocs:
http://docs.oracle.com/javase/7/docs/api/java/awt/geom/AffineTransform.html
public void rotate(double theta,
double anchorx,
double anchory)
the first argument is your rotation, the last two arguments have to be the middle of your cannon base! like screen.height and 0 for your example:
AffineTransform transform = new AffineTransform();
transform.rotate(Math.toRadians(-60), 0, Screen.height);
Shape transformed = transform.createTransformedShape(rect);
g2d.fill(transformed);
second approach could be move the middle of your rotated rectangle around the radius of your base.
like (pseudocode):
Point p = circle.getPoint();
shape.moveto(p.x-(shape.width/2),p.y-(shape.height/2));
g2d.fill(shape);

Drawing rectangles at an angle

What is a method in Java that draws a rectangle given the following:
The coordinates of the center of the square
The angle of the rectangle from vertical, in degrees
To draw a rectangle in the way you suggest you need to use the class AffineTransform. The class can be used to transform a shape in all manner of ways. To perform a rotation use:
int x = 200;
int y = 100;
int width = 50;
int height = 30;
double theta = Math.toRadians(45);
// create rect centred on the point we want to rotate it about
Rectangle2D rect = new Rectangle2D.Double(-width/2., -height/2., width, height);
AffineTransform transform = new AffineTransform();
transform.rotate(theta);
transform.translate(x, y);
// it's been while, you might have to perform the rotation and translate in the
// opposite order
Shape rotatedRect = transform.createTransformedShape(rect);
Graphics2D graphics = ...; // get it from whatever you're drawing to
graphics.draw(rotatedRect);
For the first point, you can just figure out the coordinates of the center of the square by using a distance formula, (int)Math.sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)); them divide by 2. you can do this for the width and height. I don't know enough about Java draw to give you better answers based on what was in your question but I hope that helps.
For the second, you would need to just create a polygon right?

How to draw an arc?

im trying to draw an arc - just a simple looking arc from point (x1,y1) to point (x2,y2)
how do i do that?
i been using the so complex and not freindly to user method called drawArc on Graphics class. no luck yet tho.
thats what i tried:
void drawArc(Graphics2D g, int x1, int y1, int x2, int y2) {
AffineTransform prev = g.getTransform();
double dx = x2 - x1, dy = y2 - y1;
double angle = Math.atan2(dy, dx);
int len = (int) Math.sqrt(dx*dx + dy*dy);
AffineTransform at = AffineTransform.getTranslateInstance(x1, y1);
at.rotate(angle);
g.transform(at);
g.drawArc(len/2, len/2, len ,len/2, 0, 60);
g.setTransform(prev);
}
thanks ahead.
graphics.drawLine(x1,y1,x2,y2) is the simplest possible arc that you can draw with these information.
Probably it is not what you want. If you want something more ... curvy you need to define somehow how curvy it is, in what direction. The drawArc method requires you to calculate an ellipse that touches both points. The arc is the segment of the circle between those points. There is an infinite number of possible ellipses. (The drawLine example assumes an infinite ellipse.) But this requires more information (what ellipse to chose) and some calculation.
If you want to draw curves between two points and control points (what you probably want) you need to look into QuadCurve2D or CubicCurve2D and drawShape. You can find sample code here.

Categories

Resources