Рассчитать среднюю точку кривой Безье

У меня есть функция рисовать Bezier Curve через три пункта. У меня уже есть 2 точки (начало и конец) - A и B. Как рассчитать среднюю точку между этими двумя точками, так как средняя точка всегда будет немного выше или ниже линейной функции этих двух точек.

Пример:

введите описание изображения здесь

Любые формулы, идеи будут великолепны!

3 ответа

Решение

Я думаю, это то, что вы ищете:

http://blog.sklambert.com/finding-the-control-points-of-a-bezier-curve/

Здесь подробно рассматриваются расчеты различных точек на кривой Безье.

Вы также можете быть заинтересованы в этом более конкретном примере для вашего приложения:

http://www.codeproject.com/Articles/223159/Midpoint-Algorithm-Divide-and-Conquer-Method-for-D

Если вы действительно хотите войти в это, то я предлагаю этот учебник для начинающих:

http://pomax.github.io/bezierinfo/

Кривые Безье немного сложнее, чем простые дуги. Для дуги, вы можете просто использовать эту формулу:

R = H/2 + W^2/8H

... что определенно не будет работать для кривой Безье. Например, на квадратичной кривой Безье для расчета точки необходимо использовать:

введите описание изображения здесь

Источники: http://en.wikipedia.org/wiki/B%C3%A9zier_curve, Квадратичная кривая Безье: Расчет точки

Ниже приведено то, что я использую, чтобы получить контрольную точку кривой Безье. Это должно работать для вашей проблемы, когда контрольная точка находится на кривой. Это в Swift, но вы должны быть в состоянии легко конвертировать его на другой язык. По сути, в средней точке линии (точки которой - точка1 и точка2) я вырабатываю перпендикулярную линию заданной длины. Параметр по часовой стрелке определяет, на какую сторону линии должна падать точка.

func getControlPointWithPoint1(point1:CGPoint, point2:CGPoint, length:CGFloat, clockwise:Bool) -> CGPoint {
  let angle = getAngleWithPoint1(point1, point2:point2)
  let direction = clockwise ? 1 : -1
  let perpendicularAngle = angle + (CGFloat(direction) * CGFloat((M_PI / 2)))
  let midPoint = getMidPointWithPoint1(point1, point2:point2)
  return CGPointMake(midPoint.x + (cos(perpendicularAngle) * length), midPoint.y + (sin(perpendicularAngle) * length))
}

func getAngleWithPoint1(point1:CGPoint, point2:CGPoint) -> CGFloat {
  return atan2((point2.y - point1.y), (point2.x - point1.x))
}

func getMidPointWithPoint1(point1:CGPoint, point2:CGPoint) -> CGPoint {
  return CGPointMake((point1.x + point2.x) / 2, (point1.y + point2.y) / 2)
}

Ниже показано, как это будет отображаться на диаграмме вашего письма:

c = getControlPointWithPoint1(a, point2:b, length:h, clockwise:true)

После ответа Марка, вот фрагмент в C#

public static Path DrawBezeireUsingTwoPoints(Point startPoint, Point endPoint)
{
  Path path = new Path();
  PathFigure pathFigure = new PathFigure();
  // Set up the Path to insert the segments
  PathGeometry pathGeometry = new PathGeometry();
  BezierSegment bezeireSeg;
  // Draw an ellipse passing by the 2 points and let the path cross it
  Point beziereMidPoint = CalculateBezierePoint(startPoint, endPoint, true);
  bezeireSeg = new BezierSegment(startPoint, beziereMidPoint, endPoint, true);

  pathFigure.StartPoint = startPoint;
  pathFigure.IsClosed = false;
  pathFigure.Segments.Add(bezeireSeg);

  pathGeometry.Figures.Add(pathFigure);
  path.Data = pathGeometry;
  path.Stroke = Brushes.Brown;
  path.StrokeThickness = 2;
  return path;
}

Буду рад, если вам поможет.

Это мое решение.

    Vector2 posA = sphereA.transform.position;
    Vector2 posB = sphereB.transform.position;

    Gizmos.color = Color.blue;
    Gizmos.DrawLine(posA, posB);

    float distance = Vector2.Distance(posA, posB);
    Vector2 direction = (posB - posA).normalized;

    Vector2 v2 = end - start;
    var angle = Mathf.Atan2(v2.y, v2.x) * Mathf.Rad2Deg;      

    var midStartPos = posA + direction * (distance / 2f);

    Gizmos.color = Color.red;
    Gizmos.DrawSphere(midStartPos, 0.02f);

    var height = 0.3f;

    height = Mathf.Clamp(height, 0f, Vector2.Distance(posA, posB) * 0.5f);

    angle = 90f + angle;

    var goalDirection = new Vector2(Mathf.Cos(angle * Mathf.Deg2Rad), Mathf.Sin(angle * Mathf.Deg2Rad));

    if (goalDirection.y < 0f)
    {
        goalDirection.x = -goalDirection.x;
        goalDirection.y = Mathf.Abs(goalDirection.y);
    }

    var midEndPos = midStartPos + goalDirection * height;

    Gizmos.color = Color.blue;
    Gizmos.DrawLine(midStartPos, midEndPos);

    Gizmos.color = Color.red;
    Gizmos.DrawSphere(midEndPos, 0.02f);
Другие вопросы по тегам