2

I have read similar topics in order to find solution, but with no success. What I'm trying to do is make the tool same as can be found in CorelDraw, named "Pen Tool". I did it by connecting Bezier cubic curves, but still missing one feature, which is dragging curve (not control point) in order to edit its shape.

I can successfully determine the "t" parameter on the curve where dragging should begin, but don't know how to recalculate control points of that curve.

Here I want to higlight some things related to CorelDraw''s PenTool behaviour that may be used as constaints. I've noticed that when dragging curve strictly vertically, or horizontally, control points of that Bezier curve behave accordingly, i.e. they move on their verticals, or horizontals, respectively.

So, how can I recalculate positions of control points while curve dragging?

Dr. belisarius
  • 60,527
  • 15
  • 115
  • 190
Rasa
  • 337
  • 1
  • 4
  • 10
  • You assume everyone is informed about CorelDraw behavior ... – Dr. belisarius Jan 29 '11 at 18:41
  • I thought I have been pretty clear in description of CorelDraw's PenTool behaviour that is related to question. However, you can ignore that PenTool belongs to CorelDraw. Just focus on mentioned behaviour. – Rasa Jan 29 '11 at 19:00
  • Not clear enough for me. If a Bezier is defined trough it's control points, any operation on it should be done by modifying the control points. You are explaining another kind of dragging, but it's not clear what you are dragging. The curve is an equation, whose only parms are t and the ctrl points. – Dr. belisarius Jan 29 '11 at 19:08
  • I'm dragging the curve at position "t". – Rasa Jan 29 '11 at 19:12

3 Answers3

4

Ive just look into Inkspace sources and found such code, may be it help you:

// Magic Bezier Drag Equations follow!
// "weight" describes how the influence of the drag should be distributed
// among the handles; 0 = front handle only, 1 = back handle only.
double weight, t = _t;
if (t <= 1.0 / 6.0) weight = 0;
else if (t <= 0.5) weight = (pow((6 * t - 1) / 2.0, 3)) / 2;
else if (t <= 5.0 / 6.0) weight = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5;
else weight = 1;

Geom::Point delta = new_pos - position();
Geom::Point offset0 = ((1-weight)/(3*t*(1-t)*(1-t))) * delta;
Geom::Point offset1 = (weight/(3*t*t*(1-t))) * delta;

first->front()->move(first->front()->position() + offset0);
second->back()->move(second->back()->position() + offset1);

In you case "first->front()" and "second->back()" would mean two control points

Anton Semenov
  • 6,227
  • 5
  • 41
  • 69
  • Thank you very much! I had implemented this procedure in Java, and it worked out right away. Not sure if it works the way it is working in CorelDraw, but for now it looks so similar. Will test its beahviour later. Thanks again for your help. – Rasa Jan 30 '11 at 12:19
2

The bezier curve is nothing more then two polynomials: X(t), Y(t).

The cubic one:

x = ax*t^3 + bx*t^2 + cx*t + dx
                               0 <= t <= 1
y = ay*t^3 + by*t^2 + cy*t + dy

So if you have a curve - you have the poly coefficients. If you move your point and you know it's t parameter - then you can simply recalculate the poly's coefficients - it will be a system of 6 linear equations for coefficients (for each of the point). The system is subdivided per two systems (x and y) and can be solved exactly or using some numerical methods - they are not hard too.

So your task now is to calculate control points of your curve when you know the explicit equation of your curve.

It can be also brought to the linear system. I don't know how to do it for generalized Bezier curve, but it is not hard for cubic or quadric curves.

The cubic curve via control points:

B(t) = (1-t)^3*P0 + 3(1-t)^2*t*P1 + 3(1-t)*t^2*P2 + t^3*P3

Everything you have to do is to produce the standard polynomial form (just open the brackets) and to equate the coefficients. That will provide the final system for control points!

Andrew
  • 24,218
  • 13
  • 61
  • 90
  • I'm not sure you're right. You see, I have P0, P3, t and P (point on the cubic curve that corresponds to t). These data gives to me a family of cubic curves. There is no single solution, unless some extra constrains are involved. – Rasa Jan 30 '11 at 12:25
  • Yes, you are right. As an extra condition you can use something like this. Take an extra point on a curve, that will be moved too. For example if t < 0.5 at the user taken point you can take point at t1 = t/2 and move it with a half speed of the user's point. If t > 0.5 then t1 = t + 0.5*(1 - t); – Andrew Jan 30 '11 at 13:19
  • I had that in mind, but that won't resolve the problem, because exact position of another point must be determined; its t-position is just not enough. So, proposed solution from Inkscape is good enough. I have tried it. – Rasa Jan 30 '11 at 16:22
  • You have four points - it's enough. Four - because P0, P3, the point with parameter t0, that user is moving and the point with parameter t1 is moved according to the user's one as i've said – Andrew Jan 30 '11 at 16:36
  • Suppose the user has taken a point at t=1/5. You're saying that points at t1=1/10 or t1=3/5 should have the same speed. i.e half speed of the point choosen by user? – Rasa Jan 30 '11 at 17:10
  • if t = 1/5 i think it's good to take a point t1 = 0.2 + 0.5*(1-0.2) = 0.6 and to move it too with some velocity - for example 1/2 of user's point. I think it will be good if that velocity will depend of t parameter. I don't know how the result will look exactly but you should understand that if the user moves one point on a curve there is no definite solution of how all control points should move. That's because users is interaction with 2 parameters (x, y of he's point) and two control points provide 4 parameters. So in any case you need an extra condition. I've just suggested you one of them – Andrew Jan 30 '11 at 17:27
0

When you clicks on curve, you already know position of current control point. So you can calculate offset X and offset Y from that point to mouse position. In case of mouse move, you would be able to recalculate new control point with help of X/Y offsets.

Sorry for my english

Anton Semenov
  • 6,227
  • 5
  • 41
  • 69
  • I'm not sure mouse pointer will stay at the curve when I recalculate control points positions. Mouse pointer must not fly away from curve ewhile dragging. – Rasa Jan 29 '11 at 19:13
  • I think it would be correct. In my scenarion you will move not curve but control point (with help of offsets), and in case of double prescicion usage it will give exellent results. Of course it is very difficult to position mouse pointer directly on cure (I suppose you have curve with 1px width) and in most cases mouse would be not directly on cure, so all will OK! :-) – Anton Semenov Jan 29 '11 at 19:25
  • There are 2 control points. What you advice may be OK only for t=0.5, but not for other values. – Rasa Jan 29 '11 at 19:39
  • Sorry, i thoght you use quadratic bezier curve. In case of Cubic you can move only nearest control point or both together. Analizing the behavour of coreldraw I think it moves nearest point – Anton Semenov Jan 29 '11 at 19:43
  • I've just checked it out and couldn't find any particular proportions that could be valid between displacement of curve point dragged by user and nearest control point. – Rasa Jan 29 '11 at 20:37
  • My native ideas came out. But I just look into Inkspace sources and found this function: – Anton Semenov Jan 29 '11 at 21:13