I have let's say two Path2D, one contains the other. When I move a point from first shape, the second shape move the same, but because of the angle changing, the distance between shapes changes too (and the final result...).
I have this so far, with hard coded points for the second triangle(innerTriangle):
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
class DragTest extends JPanel {
private final class MouseDrag extends MouseAdapter {
private boolean dragging = false;
private Point last;
@Override
public void mousePressed(MouseEvent m) {
if(dRect.contains(m.getPoint())){
last = m.getPoint();
dragging = isInsideRect(dRect, last);
if (!dragging) {
x = last.x;
y = last.y;
width = 0;
height = 0;
}
}
repaint();
}
@Override
public void mouseReleased(MouseEvent m) {
last = null;
dragging = false;
repaint();
}
@Override
public void mouseDragged(MouseEvent m) {
if(dRect.contains(m.getPoint())){
int dx = m.getX() - last.x;
int dy = m.getY() - last.y;
if (dragging) {
x += dx;
y += dy;
} else {
width += dx;
height += dy;
}
last = m.getPoint();
}
repaint();
}
}
private int x;
private int y;
private int width;
private int height;
private Rectangle2D.Float dRect ;
private Path2D triangle = new Path2D.Float();
private Path2D innerTriangle = new Path2D.Float();
private Point p1;
private Point p2 = new Point(5,200);
private Point p3 = new Point(400,200);
private MouseDrag mouseDrag;
public DragTest() {
setBackground(Color.WHITE);
dRect = new Rectangle2D.Float(x, y, 10+width, 10+height);
mouseDrag = new MouseDrag();
addMouseListener(mouseDrag);
addMouseMotionListener(mouseDrag);
}
public boolean isInsideRect(Shape s, Point point) {
return s.contains(point);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
dRect = new Rectangle2D.Float(x, y , 10, 10);
g2.draw(dRect);
triangle.reset();
triangle.moveTo(dRect.getCenterX(), dRect.getCenterY());
p1 = new Point((int)dRect.getCenterX(), (int)dRect.getCenterY());
triangle.lineTo(p2.x, p2.y);
triangle.lineTo(p3.x, p3.y);
triangle.closePath();
innerTriangle.reset();
innerTriangle.moveTo(p1.x+10, p1.y+17);
innerTriangle.lineTo(p2.x+10, p2.y-10);
innerTriangle.lineTo(p3.x-47, p3.y-10);
innerTriangle.closePath();
g2.draw(triangle);
g2.draw(innerTriangle);
g2.dispose();
}
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setSize(800, 600);
jFrame.add(new DragTest());
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
How can I maintain the same distance all around (say 10px), programmatically?
The distance between the outer triangle and the red (inner) triangle should be the same always, in all directions. Any idea?
Currently I'm working on something:
// Calculate distance from point to line
public double pointToLineDistance(Point A, Point B, Point P) {
double normalLength = Math.sqrt((B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y));
return Math.abs((P.x-A.x)*(B.y-A.y)-(P.y-A.y)*(B.x-A.x))/normalLength;
}
// initially set :
// pi1.x = p1.x;
// pi1.y = p1.y;
// -------------------- Then ------------------------------
while(pointToLineDistance(p1, p3, pi1) == 10 && pointToLineDistance(p1, p2, pi1) == 10){
pi1.y++;
pi1.x++;
pi1.setLocation(pi1.x, pi1.y);
}
... but doesn't work. HELP!!! :)
Thank You!
This problem needs a illistration to help explain. The solution is for one corner but the process will work for as many corners as you want.
Given two lines joined at one end find the two line offset by a fixed amount from both lines
Bold letters (example A) represent points. Lines as bold joined letters from start to end (example AB is line from A to B and BA is the line from B to A)
Given the lines AB and BC find the lines A1D and DC1 so that the area x distance from the original lines.
// all variables are assumed declared and floats or doubles (up to you)
Ax = 10; // x of Point A
Ay = 200; // y of A
Bx = 200; // x,y of B
By = 200;
Cx = 40; // C
Cy = 10;
Dist = 40; // distance from the line
Looking at the image we can see some nice symmetry that can be exploited to find the solution. The lines EB, BF, FD and DE are all the same length. That means that if we solve the right triangle gBF we can move along the line BA from B to g and from g to h as gh is the same length as FB
From this point the line AB is turned around to BA
To find the point A1 we find the normalised vector along the line BA
Finding A1
// get the vector from B to A and normalise it
BAx = Ax - Bx;
BAy = Ay - By;
leng = Math.sqrt(BAx * BAx + BAy * BAy);
BAx /= leng; // The vector BA is 1 pixel (unit long)
BAy /= leng;
The normal moves along the line to go at 90 deg just swap x
and y
negating y
A1x = Ax - BAy * Dist;
A1y = Ay + BAx * Dist;
Now do the same for the point C1
BCx = Cx - Bx;
BCy = Cy - By;
leng = Math.sqrt(BCx * BCx + BCy * BCy);
BCx /= leng;
BCy /= leng;
C1x = Cx + BCy * Dist; // move in the opposite direction than from A
C1y = Cy - BCx * Dist;
If you only needed to find D (eg you are doing this on a closed line, triangle) you still have to get the normalised vectors BA and BC that were worked out above. BAx
, BAy
and BCx
, BCy
To find the sin of the angle EBF use get the cross product of the two normalised vectors BA and BC. The sin of an angle relates the opposite side of a triangle Fg to the Hypotenuse BF as sin(ang) = opp/hypt
cross = BAx * BCy - BAy * BCx; // gets the sin of the angle
// you should check cross of zero. If so there is no solution
FBlen = Dist / cross; // gets the hypot the length of FB
Now we have FB we know the distance gh we could get gB as we have two sides of a right triangle and the length of gB = sqrt(FB*FB+Dist*Dist)
but this will become an issue if the angle of ABC is greater than 90 deg. Not only do we need to know the length but the direction (positive or negative).
We can solve for Bg using the dot product which finds the cosine of the angle ABC which relates the hypotenuse to the adjacent side of a right triangle cos(ang) = BF/Bg
dot = BAx * BCx + BAy * BCy;
Bglen = FBlen * dot;
Now we can move along the line BA to g then to h then turn 90deg and out to D
// move from B to h using the normal vec of the line BA time the sum
// of the length FB
hx = Bx + BAx * (FBlen + BgLen);
hy = By + BAy * (FBlen + BgLen);
Dx = hx - BAy * Dist; // then at 90 deg dist along to D
Dy = hy + BAx * Dist;
And you are all done you have the points A1, D, C1
You may also prefer to use a vector lib to do the adding, normalising,cross product etc...
Ax = 10; // x of Point A
Ay = 200; // y of A
Bx = 200; // x,y of B
By = 200;
Cx = 40; // C
Cy = 10;
Dist = 40; // dist out
BAx = Ax - Bx;
BAy = Ay - By;
BCx = Cx - Bx;
BCy = Cy - By;
leng = Math.sqrt(BAx * BAx + BAy * BAy);
BAx /= leng;
BAy /= leng;
leng = Math.sqrt(BCx * BCx + BCy * BCy);
BCx /= leng;
BCy /= leng;
// get inside end points
A1x = Ax - BAy * Dist;
A1y = Ay + BAx * Dist;
C1x = Cx + BCy * Dist;
C1y = Cy - BCx * Dist;
FBlen = Dist / (BAx * BCy - BAy * BCx);
FBlen += FBlen * (BAx * BCx + BAy * BCy);
Dx = Bx + BAx * FBlen - BAy * Dist;;
Dy = By + BAy * FBlen + BAx * Dist;
You can do this for any number of lines as long as you go in the same direction and that your vectors are from the corners out. There are a few caveats.
Mitering a corner. The above answer has given you the information you need to solve the above image. The distance DF is fixed to max miter limit, if the point B is further than F from D then find the point F. Look for symmetry and like triangles to find the other points.
If you are making long lines you will be best of doing thein on each side of the line. By defining the center not the edge you get a better result.