2014-09-09 2 views
0

ОК, поэтому у меня есть приложение, которое использует кривые переменной ширины, которые привязаны к узлам, и я получил его работу отлично с одной контрольной точкой. Я сам создаю контрольную точку, в зависимости от местоположения кривых относительно прикрепленного узла. Так что кривая не изогнута вообще, когда угол к узлу равен 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

Большое спасибо за любую помощь.

+0

добро пожаловать в «почему кривые Безье сложны». http://pomax.github.io/bezierinfo/#offsetting –

ответ

0

У меня это работает отлично! Единственное, что я на самом деле ошибался, это то, что я рисую правильную кривую «вверх ногами», поэтому мне просто нужно было передать первую контрольную точку как вторую.

Смежные вопросы