trigonometry - Java Draw Arc Between 2 Points -
i'm having trouble drawing smallest arc described 3 points: arc center, "anchored" end point, , second point gives other end of arc determining radius. used law of cosines determine length of arc , tried using atan starting degree, starting position arc off.
i managed arc lock onto anchor point (x1,y1) when it's in quadrant 2, work when in quadrant 2.
solutions can see have bunch of if-statements determine location of 2 points relative each other, i'm curious if i'm overlooking simple. appreciated.
sscce:
import javax.swing.jcomponent; import javax.swing.jframe; import java.awt.event.mouseevent; import java.awt.event.mouselistener; import java.awt.geom.*; import java.awt.*; import java.util.*; class canvas extends jcomponent { float circlex, circley, x1, y1, x2, y2, dx, dy, dx2, dy2, radius, radius2; random random = new random(); public canvas() { //setup. x1 = random.nextint(250); y1 = random.nextint(250); //cant have x2 == circlex while (x1 == 150 || y1 == 150) { x1 = random.nextint(250); y1 = random.nextint(250); } circlex = 150; //circle center dead center. circley = 150; //radius between 2 points must equal. dx = math.abs(circlex-x1); dy = math.abs(circley-y1); //c^2 = a^2 + b^2 solve radius radius = (float) math.sqrt((float)math.pow(dx, 2) + (float)math.pow(dy, 2)); //2nd random point x2 = random.nextint(250); y2 = random.nextint(250); //i need push out radius length, because radius equal both points. dx2 = math.abs(circlex-x2); dy2 = math.abs(circley-y2); radius2 = (float) math.sqrt((float)math.pow(dx2, 2) + (float)math.pow(dy2, 2)); dx2 *= radius/radius2; dy2 *= radius/radius2; y2 = circley+dy2; x2 = circlex+dx2; //radius equal both points. } public void paintcomponent(graphics g2) { graphics2d g = (graphics2d) g2; g.setrenderinghint(renderinghints.key_antialiasing, renderinghints.value_antialias_on); g.setstroke(new basicstroke(2.0f, basicstroke.cap_butt, basicstroke.join_bevel)); arc2d.float centerpoint = new arc2d.float(150-2,150-2,4,4, 0, 360, arc2d.open); arc2d.float point1 = new arc2d.float(x1-2, y1-2, 4, 4, 0, 360, arc2d.open); arc2d.float point2 = new arc2d.float(x2-2, y2-2, 4, 4, 0, 360, arc2d.open); //3 points drawn in black g.setcolor(color.black); g.draw(centerpoint); g.draw(point1); g.draw(point2); float start = 0; float distance; //form right triangle find length of hypotenuse. distance = (float) math.sqrt(math.pow(math.abs(x2-x1),2) + math.pow(math.abs(y2-y1), 2)); //law of cosines determine internal angle between 2 points. distance = (float) (math.acos(((radius*radius) + (radius*radius) - (distance*distance)) / (2*radius*radius)) * 180/math.pi); float deltay = circley - y1; float deltax = circlex - x1; float deltay2 = circley - y2; float deltax2 = circlex - x2; float angleindegrees = (float) ((float) math.atan((float) (deltay / deltax)) * 180 / math.pi); float angleindegrees2 = (float) ((float) math.atan((float) (deltay2 / deltax2)) * 180 / math.pi); start = angleindegrees; //q2 works. if (x1 < circlex) { if (y1 < circley) { start*=-1; start+=180; } else if (y2 > circlex) { start+=180; start+=distance; } } //system.out.println("start: " + start); //arc drawn in blue g.setcolor(color.blue); arc2d.float arc = new arc2d.float(circlex-radius, //center x circley-radius, //center y rotates around point. radius*2, radius*2, start, //start degree distance, //distance travel arc2d.open); //type of arc. g.draw(arc); } } public class angle implements mouselistener { canvas view; jframe window; public angle() { window = new jframe(); view = new canvas(); view.addmouselistener(this); window.setdefaultcloseoperation(jframe.exit_on_close); window.setbounds(30, 30, 400, 400); window.getcontentpane().add(view); window.setvisible(true); } public static void main(string[] a) { new angle(); } @override public void mouseclicked(mouseevent arg0) { window.getcontentpane().remove(view); view = new canvas(); window.getcontentpane().add(view); view.addmouselistener(this); view.revalidate(); view.repaint(); } @override public void mouseentered(mouseevent arg0) { // todo auto-generated method stub } @override public void mouseexited(mouseevent arg0) { // todo auto-generated method stub } @override public void mousepressed(mouseevent arg0) { // todo auto-generated method stub } @override public void mousereleased(mouseevent arg0) { // todo auto-generated method stub } }
perhaps help. tests click , drag set 2 points rather random numbers. it's considerably simpler attempting , other solutions posted far.
notes:
math.atan2()
friend in problems this.- little helper functions make easier reason code.
- it's best practice use instance variables independent values , compute dependent values in local variables.
- my code fixes swing usage problems calling swing functions main thread.
code follows:
import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import javax.swing.*; import javax.swing.event.mouseinputadapter; class testcanvas extends jcomponent { float x0 = 150f, y0 = 150f; // arc center. subscript 0 used center throughout. float xa = 200f, ya = 150f; // arc anchor point. subscript anchor. float xd = 150f, yd = 50f; // point determining arc angle. subscript d determiner. // return distance point arc center. float dist0(float x, float y) { return (float)math.sqrt(sqr(x - x0) + sqr(y - y0)); } // return polar angle of point relative arc center. float angle0(float x, float y) { return (float)math.todegrees(math.atan2(y0 - y, x - x0)); } @override protected void paintcomponent(graphics g0) { graphics2d g = (graphics2d) g0; // can draw center point. dot(g, x0, y0); // radii of anchor , det point. float ra = dist0(xa, ya); float rd = dist0(xd, yd); // if either 0 there's nothing else draw. if (ra == 0 || rd == 0) { return; } // angles center points. float aa = angle0(xa, ya); float ad = angle0(xd, yd); // (xb, yb) work fine, too. // draw arc , other dots. g.draw(new arc2d.float(x0 - ra, y0 - ra, // box upper left 2 * ra, 2 * ra, // box width , height aa, anglediff(aa, ad), // angle start, extent arc2d.open)); dot(g, xa, ya); // use similar triangles second dot location. float xb = x0 + (xd - x0) * ra / rd; float yb = y0 + (yd - y0) * ra / rd; dot(g, xb, yb); } // helper functions. // draw small dot current color. static void dot(graphics2d g, float x, float y) { final int rad = 2; g.fill(new ellipse2d.float(x - rad, y - rad, 2 * rad, 2 * rad)); } // return square of float. static float sqr(float x) { return x * x; } // find angular difference between , b, -180 <= diff < 180. static float anglediff(float a, float b) { float d = b - a; while (d >= 180f) { d -= 360f; } while (d < -180f) { d += 360f; } return d; } // construct test canvas mouse handling. testcanvas() { addmouselistener(mouselistener); addmousemotionlistener(mouselistener); } // listener changes arc parameters click , drag. mouseinputadapter mouselistener = new mouseinputadapter() { boolean mousedown = false; // left mouse button down? @override public void mousepressed(mouseevent e) { if (e.getbutton() == mouseevent.button1) { mousedown = true; xa = xd = e.getx(); ya = yd = e.gety(); repaint(); } } @override public void mousereleased(mouseevent e) { if (e.getbutton() == mouseevent.button1) { mousedown = false; } } @override public void mousedragged(mouseevent e) { if (mousedown) { xd = e.getx(); yd = e.gety(); repaint(); } } }; } public class test extends jframe { public test() { setsize(400, 400); setlocationrelativeto(null); setdefaultcloseoperation(jframe.exit_on_close); getcontentpane().add(new testcanvas()); } public static void main(string[] args) { // swing code must run in ui thread, // must invoke setvisible rather calling it. swingutilities.invokelater(new runnable() { @override public void run() { new test().setvisible(true); } }); } }
Comments
Post a Comment