Найти новую контрольную точку при изменении конечной точки в кубической кривой безье - программирование
Подтвердить что ты не робот

Найти новую контрольную точку при изменении конечной точки в кубической кривой безье

Я использую кубическую логику кривой безье в моем приложении Android.

Я реализовал кубический код кривой безье на холсте в onDraw пользовательского вида.

// Path to draw cubic bezier curve
Path cubePath = new Path();

// Move to startPoint(200,200) (P0)
cubePath.moveTo(200,200);

// Cubic to with ControlPoint1(200,100) (C1), ControlPoint2(300,100) (C2) , EndPoint(300,200) (P1)
cubePath.cubicTo(200,100,300,100,300,200);

// Draw on Canvas
canvas.drawPath(cubePath, paint);

Я визуализирую код выше на следующем изображении.

Output of above code

[Обновлено]

Logic for selecting first control points, I've taken ,
baseX = 200 , baseY = 200 and curve_size = X of Endpoint - X of Start Point

Start Point     : x = baseX and y = baseY
Control Point 1 : x = baseX and y =  baseY - curve_size
Control Point 2 : x = baseX + curve_size and y =  baseY - curve_size
End Point       : x = baseX + curve_size and y = baseY

Я хочу разрешить пользователю изменять EndPoint кривой выше, и на основе новых конечных точек я аннулирую холст.

Но проблема в том, что Curve поддерживает две контрольные точки, которые необходимо пересчитывать при изменении в EndPoint.

Например, я просто хочу найти новые контрольные точки, когда значение EndPoint изменится с (300,200) до (250,250)

Как на следующем изображении:

New Image

Пожалуйста, помогите мне рассчитать два новых контрольных точки на основе новой конечной точки, чтобы форма кривой сохранялась так же, как и предыдущая конечная точка.

Я ссылаюсь на ссылочные ссылки во время поиска:

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

http://jsfiddle.net/hitesh24by365/jHbVE/3/

http://en.wikipedia.org/wiki/B%C3%A9zier_curve

http://cubic-bezier.com/

Любая ссылка также была оценена в ответ на этот вопрос.

4b9b3361

Ответ 1

изменение конечной точки означает две вещи: поворот вдоль Р1 и коэффициент масштабирования.

Коэффициент масштабирования (позволяет называть его s) равен len (p1 - p0)/len (p2 - p0)

Для коэффициента вращения (давайте назовем его r) отложим вас на Вычисление угла между тремя точками в android, что также дает конкретную реализацию платформы, но вы может проверить правильность путем масштабирования /rotationg p1 по отношению к p0, и вы должны получить p2 в результате.

next, примените масштабирование и поворот относительно p0-c1 и c2. для удобства я вызову новый c1 'd1' и новый d2.

d1 = rot(c1 - p0, factor) * s + p0
d2 = rot(c2 - p0, factor) * s + p0

чтобы определить некоторый псевдокод для rot() (вращение http://en.wikipedia.org/wiki/Rotation_%28mathematics%29)

rot(point p, double angle){
  point q;
  q.x = p.x * cos(angle) - p.y * sin(angle);
  q.y = p.x * sin(angle) + p.y * cos(angle);
}

Кривая Безье теперь масштабируется и вращается относительно p0, p1 изменен на p2,

Ответ 2

Во-первых, я попрошу вас изучить следующие статьи:

То, что вы пытаетесь реализовать, - это кусочно-композитная кривая Безье. На странице "Сводка" для n контрольных точек (включая начало/конец) вы получаете (n - 1)/3 кусочно кривые Безье.

Контрольные точки образуют кривую буквально. Если вы не дадите правильные контрольные точки с новой точкой, вы не сможете создать плавно связанную кривую Безье. Генерация их не будет работать, поскольку она слишком сложна и не существует общепринятого способа.

Если у вас нет/хотите предоставить дополнительные контрольные точки, вы должны использовать сплайн Catmull-Rom, который проходит через все контрольные точки и будет C1 непрерывным (производная непрерывна в любой точке кривой).

Ссылки для Catmull Rom Spline в java/android:

Нижняя строка - если у вас нет контрольных точек, не используйте кубическую кривую безье. Их создание - проблема не решения.

Ответ 3

Кажется, что вы здесь вращаетесь и масштабируете квадрат, где вы знаете нижние две точки, и вам нужно рассчитать два других. Две известные точки образуют два треугольника с двумя другими, поэтому нам просто нужно найти третью точку треугольника. Предположим, что конечная точка x1, y1:

PointF c1 = calculateTriangle(x0, y0, x1, y1, true); //find left third point
PointF c2 = calculateTriangle(x0, y0, x1, y1, false); //find right third point

cubePath.reset();
cubePath.moveTo(x0, y0);
cubePath.cubicTo(c1.x, c1.y, c2.x, c2.y, x1, y1);


private PointF calculateTriangle(float x1, float y1, float x2, float y2, boolean left) {
                PointF result = new PointF(0,0);
                float dy = y2 - y1;
                float dx = x2 - x1;
                float dangle = (float) (Math.atan2(dy, dx) - Math.PI /2f);
                float sideDist = (float) Math.sqrt(dx * dx + dy * dy); //square
                if (left){
                    result.x = (int) (Math.cos(dangle) * sideDist + x1);
                    result.y = (int) (Math.sin(dangle) * sideDist + y1);                    
                }else{
                    result.x = (int) (Math.cos(dangle) * sideDist + x2);
                    result.y = (int) (Math.sin(dangle) * sideDist + y2);
                }
                return result;
            }

...

Есть и другой способ сделать это, когда неважно, сколько у вас очков между первой и последней точкой пути или события его формы.

//Find scale
Float oldDist = (float) Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
Float newDist = (float) Math.sqrt((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0)); 
Float scale = newDist/oldDist;

//find angle
Float oldAngle = (float) (Math.atan2(y1 - y0, x1 - x0) - Math.PI /2f);
Float newAngle = (float) (Math.atan2(y2 - y0, x2 - x0) - Math.PI /2f);
Float angle = newAngle - oldAngle;

//set matrix
Matrix matrix = new Matrix();
matrix.postScale(scale, scale, x0, y0);
matrix.postRotate(angle, x0, y0);

//transform the path
cubePath.transform(matrix);

Ответ 4

Небольшой вариант по предложению Лумиса

// Find scale
Float oldDist = (float) Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
Float newDist = (float) Math.sqrt((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0)); 
Float scale = newDist/oldDist;

// Find angle
Float oldAngle = (float) (Math.atan2(y1 - y0, x1 - x0));
Float newAngle = (float) (Math.atan2(y2 - y0, x2 - x0));
Float angle = newAngle - oldAngle;

Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
matrix.postRotate(angle);

float[] p = { c1.x, c1.y, c2.x, c2.y };
matrix.mapVectors(p);
PointF newC1 = new PointF(p[0], p[1]);
PointF newC2 = new PointF(p[2], p[3]);