ОК, поэтому у меня есть приложение, которое использует кривые переменной ширины, которые привязаны к узлам, и я получил его работу отлично с одной контрольной точкой. Я сам создаю контрольную точку, в зависимости от местоположения кривых относительно прикрепленного узла. Так что кривая не изогнута вообще, когда угол к узлу равен 0, 90, 180, 270 или 360.Создание контрольных точек для переменной ширины Curve
Как я уже сказал, я использую только одну контрольную точку, и теперь я хочу добавить еще одну контрольная точка, чтобы получить более плавную кривую. Но у меня возникают проблемы с пониманием того, что я делаю неправильно здесь.
Вот соответствующие фрагменты кода. Надеюсь, они относительно просты.
// Creates, or "projects" a Vector from the given angle and length
public static Point2D project(double angle, double length) {
double x = length;
double y = 0;
double cos = Math.cos(Math.toRadians(angle - 90));
double sin = Math.sin(Math.toRadians(angle - 90));
double newX = x * cos - y * sin;
double newY = x * sin + y * cos;
return new Point2D(newX, newY);
}
// Linear interpolation
public static double lerp(double a, double b, double ratio) {
return a + ratio * (b - a);
}
// Linear interpolation for a line
public static Point2D interpolate(Point2D start, Point2D end, double ratio) {
double x = lerp(start.getX(), end.getX(), ratio);
double y = lerp(start.getY(), end.getY(), ratio);
return new Point2D(x, y);
}
// Generates one (or two) control points for a Bezier Curve
public static PointPair calculateCurveControls(Point2D from, Point2D to, double angle) {
double curvatureAmount = 0;
double curvatureDirection = 0;
if (angle >= 0 && angle <= 45) {
curvatureDirection = 90;
curvatureAmount = lerp(0, 1, angle/45);
}
if (angle > 45 && angle <= 90) {
curvatureDirection = 90;
curvatureAmount = lerp(1, 0, (angle - 45)/45);
}
if (angle > 90 && angle <= 135) {
curvatureDirection = -90;
curvatureAmount = lerp(0, 1, (angle - 90)/45);
}
if (angle > 135 && angle <= 180) {
curvatureDirection = -90;
curvatureAmount = lerp(1, 0, (angle - 135)/45);
}
if (angle > 180 && angle <= 225) {
curvatureDirection = 90;
curvatureAmount = lerp(0, 1, (angle - 180)/45);
}
if (angle > 225 && angle <= 270) {
curvatureDirection = 90;
curvatureAmount = lerp(1, 0, (angle - 225)/45);
}
if (angle > 270 && angle <= 315) {
curvatureDirection = -90;
curvatureAmount = lerp(0, 1, (angle - 270)/45);
}
if (angle > 315 && angle <= 360) {
curvatureDirection = -90;
curvatureAmount = lerp(1, 0, (angle - 315)/45);
}
double distance = from.distance(to);
// Only one control point, this works just fine!
// Point2D midpoint = interpolate(from, to, 0.5);
// Point2D c1 = project(angle + curvatureDirection + 180, curvatureAmount * (distance * 0.15f));
// c1 = c1.add(midpoint);
// Point2D c2 = new Point2D(c1.getX(), c1.getY());
// An attempt to generate two control points
Point2D first = interpolate(from, to, 0.25);
Point2D second = interpolate(from, to, 0.75);
Point2D c1 = project(angle + curvatureDirection + 180, curvatureAmount * (distance * 0.15));
c1 = c1.add(first);
Point2D c2 = project(angle + curvatureDirection + 180, curvatureAmount * (distance * 0.15));
c2 = c2.add(second);
return new PointPair(c1, c2);
}
Я создал некоторые визуальные средства в моем приложении, чтобы отобразить контрольные точки и прямую линию для кривого ... но я до сих пор не могу за жизнь мне понять, что я делаю неправильно .. контрольные точки выглядят так, как будто они находятся в правильном положении независимо от угла кривой.
У меня есть подозрение, что я делаю что-то не так в части «рендеринга» кода, которая, однако, работает нормально, когда я использую только одну контрольную точку (т. Е. Обе контрольные точки одинаковы). Именно здесь:
// A method from a custom Curve class, which uses a Path to render a variable width curve
public void set(Point2D from, Point2D to) {
path.getElements().clear();
this.from = from;
this.to = to;
if (developerMode) {
line.setStartX(from.getX());
line.setStartY(from.getY());
line.setEndX(to.getX());
line.setEndY(to.getY());
}
double angle = Utils.angle(from, to);
Point2D leftStart = Utils.project(angle - 90, thicknessStart/2);
leftStart = leftStart.add(from);
MoveTo moveLeftStart = new MoveTo();
moveLeftStart.setX(leftStart.getX());
moveLeftStart.setY(leftStart.getY());
Point2D leftEnd = Utils.project(angle - 90, thicknessEnd/2);
leftEnd = leftEnd.add(to);
MoveTo moveLeftEnd = new MoveTo();
moveLeftEnd.setX(leftEnd.getX());
moveLeftEnd.setY(leftEnd.getY());
Point2D rightStart = Utils.project(angle + 90, thicknessStart/2);
rightStart = rightStart.add(from);
MoveTo moveRightStart = new MoveTo();
moveRightStart.setX(rightStart.getX());
moveRightStart.setY(rightStart.getY());
Point2D rightEnd = Utils.project(angle + 90, thicknessEnd/2);
rightEnd = rightEnd.add(to);
MoveTo moveRightEnd = new MoveTo();
moveRightEnd.setX(rightEnd.getX());
moveRightEnd.setY(rightEnd.getY());
Utils.PointPair cc1 = Utils.calculateCurveControls(leftStart, leftEnd, angle);
CubicCurveTo curveLeft = new CubicCurveTo();
curveLeft.setX(leftEnd.getX());
curveLeft.setY(leftEnd.getY());
curveLeft.setControlX1(cc1.p1.getX());
curveLeft.setControlY1(cc1.p1.getY());
curveLeft.setControlX2(cc1.p2.getX());
curveLeft.setControlY2(cc1.p2.getY());
if (developerMode) {
c11.setLayoutX(cc1.p1.getX());
c11.setLayoutY(cc1.p1.getY());
c12.setLayoutX(cc1.p2.getX());
c12.setLayoutY(cc1.p2.getY());
}
Utils.PointPair cc2 = Utils.calculateCurveControls(rightStart, rightEnd, angle);
CubicCurveTo curveRight = new CubicCurveTo();
curveRight.setX(rightStart.getX());
curveRight.setY(rightStart.getY());
curveRight.setControlX1(cc2.p1.getX());
curveRight.setControlY1(cc2.p1.getY());
curveRight.setControlX2(cc2.p2.getX());
curveRight.setControlY2(cc2.p2.getY());
if (developerMode) {
c21.setLayoutX(cc2.p1.getX());
c21.setLayoutY(cc2.p1.getY());
c22.setLayoutX(cc2.p2.getX());
c22.setLayoutY(cc2.p2.getY());
}
path.getElements().add(moveLeftStart);
path.getElements().add(curveLeft);
path.getElements().add(new LineTo(moveRightEnd.getX(), moveRightEnd.getY()));
path.getElements().add(curveRight);
path.getElements().add(new LineTo(moveLeftStart.getX(), moveLeftStart.getY()));
}
Вот скриншот неправильно изогнутой кривой, линия между кривой и контрольные точки: http://i.imgur.com/JG21U0T.png
Большое спасибо за любую помощь.
добро пожаловать в «почему кривые Безье сложны». http://pomax.github.io/bezierinfo/#offsetting –