How to draw a curve that passes through three points?

牧云@^-^@ 提交于 2021-01-27 10:43:19

问题


I'm trying to create a curve that passes through three given points in Java (I'm drawing the curves through a class that extends JPanel). How can I make it?

enter image description here


回答1:


You should look into something like Catmull-Rom splines, which are basically curves that pass through a number of control points (in your case your three points).

Here is an example I found after a quick google: http://www.mvps.org/directx/articles/catmull/

Hope this helps :)




回答2:


A circle will pass through three points on a plane. This page explains the geometery: http://www.mathopenref.com/const3pointcircle.html




回答3:


I just spent some time getting this working in a robust way. There's a few supporting functions, followed by the thing that creates an Arc2D out of three points of a circle. For my purposes, I have a start and end points, as well as an intermediate 'mid' point (though it doesn't actually have to be in the middle---its purpose is to tell me which arc of the circle I want).

Here are direct links to the source:

org.six11.util.gui.shape.ShapeFactory

org.six11.util.pen.Functions

public static Pt getCircleCenter(Pt a, Pt b, Pt c) {
  double ax = a.getX();
  double ay = a.getY();
  double bx = b.getX();
  double by = b.getY();
  double cx = c.getX();
  double cy = c.getY();

  double A = bx - ax;
  double B = by - ay;
  double C = cx - ax;
  double D = cy - ay;

  double E = A * (ax + bx) + B * (ay + by);
  double F = C * (ax + cx) + D * (ay + cy);

  double G = 2 * (A * (cy - by) - B * (cx - bx));
  if (G == 0.0)
    return null; // a, b, c must be collinear

  double px = (D * E - B * F) / G;
  double py = (A * F - C * E) / G;
  return new Pt(px, py);
}

public static double makeAnglePositive(double angleDegrees) {
  double ret = angleDegrees;
  if (angleDegrees < 0) {
    ret = 360 + angleDegrees;
  }
  return ret;
}

public static double getNearestAnglePhase(double limitDegrees, double sourceDegrees, int dir) {
  double value = sourceDegrees;
  if (dir > 0) {
    while (value < limitDegrees) {
      value += 360.0;
    }
  } else if (dir < 0) {
    while (value > limitDegrees) {
      value -= 360.0;
    }
  }
  return value;
}

public static Arc2D makeArc(Pt s, Pt mid, Pt e) {
  Pt c = Functions.getCircleCenter(s, mid, e);
  double radius = c.distance(s);

  double startAngle = Functions.makeAnglePositive(Math.toDegrees(-Math
      .atan2(s.y - c.y, s.x - c.x)));
  double midAngle = Functions.makeAnglePositive(Math.toDegrees(-Math.atan2(mid.y - c.y, mid.x
      - c.x)));
  double endAngle = Functions
      .makeAnglePositive(Math.toDegrees(-Math.atan2(e.y - c.y, e.x - c.x)));

  // Now compute the phase-adjusted angles begining from startAngle, moving positive and negative.
  double midDecreasing = Functions.getNearestAnglePhase(startAngle, midAngle, -1);
  double midIncreasing = Functions.getNearestAnglePhase(startAngle, midAngle, 1);
  double endDecreasing = Functions.getNearestAnglePhase(midDecreasing, endAngle, -1);
  double endIncreasing = Functions.getNearestAnglePhase(midIncreasing, endAngle, 1);

  // Each path from start -> mid -> end is technically, but one will wrap around the entire
  // circle, which isn't what we want. Pick the one that with the smaller angular change.
  double extent = 0;
  if (Math.abs(endDecreasing - startAngle) < Math.abs(endIncreasing - startAngle)) {
    extent = endDecreasing - startAngle;
  } else {
    extent = endIncreasing - startAngle;
  }

  return new Arc2D.Double(c.x - radius, c.y - radius, radius * 2, radius * 2, startAngle, extent,
      Arc2D.OPEN);
}



回答4:


try a google search on bezier splines. this may be a 2D solution, but should be extensible to 3D if you need it.

basically, using the three points as parameters you can get an 2nd order polynomial that fits the three points .. AND its extensible, if you have N points you get an N-1 order polynomial that parametrically generates all the points from the 1st to the last, as you 'tune' a scalar parameter, oft denoted as 's'.

edit/added:

as was pointed out (credit CapBBeard!), Beziers don't actually hit the middle points. Lagrangian interpolation does actually hit the points, but gets ugly even more quickly as the number of points grows. (something like O(n) polynomial fractions each of order N)




回答5:


use 2 curves
curveLine1 created with 3 points : P1, C1, E1.
curveLine2 created with 3 points : P2 = E1, C2, E2.
make C1, E1, C2 in 1 line.
View example here : http://i.stack.imgur.com/I901q.png

QuadCurve2D.Double curveLine1 = new QuadCurve2D.Double(30, 75, 195, 23, 280, 143);
//QuadCurve2D.Double curveLine1 = new QuadCurve2D.Double(P1.x, P1.y, C1.x, C1.y, E1.x, E1.y);
QuadCurve2D.Double curveLine2 = new QuadCurve2D.Double(280, 143, 366, 260, 466, 193);
//QuadCurve2D.Double curveLine2 = new QuadCurve2D.Double(E1.x, E1.y, C2.x, C2.y, E2.x, E2.y);
Graphics2D g2 = (Graphics2D) g;
g2.draw(curveLine1);
g2.draw(curveLine2);


来源:https://stackoverflow.com/questions/1089719/how-to-draw-a-curve-that-passes-through-three-points

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!