8

I want to make a 'named' bezier curve. I want it to be one-word named so I don't have to worry about word-wrap.

I make bezier curve via P5 bezier(sx,sy,c1x,c1y,c2x,c2y,ex,ey) function and I want a string to be shown in the middle of bezier curve. But I don't know how to find 'the middle' of curve.

For now my result looks like this (I don't know where to start picking up this problem, so I went with the easier way of just printing text on a start of curve):

r1

But I want it to look like this:

r2

This means that I need P1 and P2 coordinates:

r3

Sorry for paint, but I don't have my code yet. As soon as I will have my hands on it I will add it here.

Here is code that draws a curve:

let
b = dest.inTriangle.middle, // destination triangle
g = this.outTriangle.p3,    // tip of out triangle
c = {x:b.x-g.x,y:b.y-g.y},  // distance between objects
r1 = {},                    // bezier point 1
r2 = {};                    // bezier point 2
if(c.x > 0){
    // b is on left
    r1 = {
        x: g.x + c.x/2,
        y: g.y
    };
    r2 = {
        x: b.x - c.x/2,
        y: b.y
    };
    }
else {
    // b is on right
    r1 = {
        x: g.x - c.x/2,
        y: g.y + c.y
    };
    r2 = {
        x: b.x + c.x/2,
        y: b.y - c.y
    };
}
noFill();
stroke(0);
bezier(
    g.x, g.y,
    r1.x, r1.y,
    r2.x, r2.y,
    b.x, b.y
);
noStroke();
fill(0);
text(this.name, g.x, (g.y-this.h/2))
Kevin Workman
  • 41,537
  • 9
  • 68
  • 107
SkillGG
  • 647
  • 4
  • 18

2 Answers2

5

You can use the bezierPoint() function that comes with P5.js.

From the reference:

noFill();
var x1 = 85,
 x2 = 10,
 x3 = 90,
 x4 = 15;
var y1 = 20,
 y2 = 10,
 y3 = 90,
 y4 = 80;
bezier(x1, y1, x2, y2, x3, y3, x4, y4);
fill(255);
var steps = 10;
for (var i = 0; i <= steps; i++) {
  var t = i / steps;
  var x = bezierPoint(x1, x2, x3, x4, t);
  var y = bezierPoint(y1, y2, y3, y4, t);
  ellipse(x, y, 5, 5);
}

points drawn on curve

You'd probably want to use a value of 0.5 for t to get the midpoint.

Kevin Workman
  • 41,537
  • 9
  • 68
  • 107
  • Thanks! I wasn't sure if this exist. Now I know it does! I checked reference twice, but I think I'm blind or something. :) Thanks for help. – SkillGG Jan 16 '19 at 20:28
3

So, the formula to translate the 4 points in a function over time is the following (image from wikipedia):

enter image description here

Since you want the middle, and t ranges from 0 to 1, you just have to set t = 1/2

So

B(1/2) = 1/8 P0 + 3/8 P1 + 3/8 P2 + 1/8 P3

  • When a curve is given by a nonlinear parameterization (with `t` ranging over `[0,1]`), the point which is midpoint in arc length will typically *not* be the point which occurs at `t = 1/2`. I think that your answer is fallacious. On the other hand, this might be a reasonable heuristic for OP's problem, so I think that it has some merit. – John Coleman Jan 16 '19 at 12:05
  • @JohnColeman That's true, but I supposed that the user just wanted all the labels to be on the same column, and maybe animate the position over time like many cubic-bezier generators do. In this scenario, the x-coordinate is known and the y-coordinate can be found with that formula. If he wants the exact middle of the curve, the problem isn't so trivial but I think it's still analytically solvable – Christian Vincenzo Traina Jan 16 '19 at 13:23
  • 2
    Since OP seems to have something symmetric in mind, this should work, so (+1). Even in the nonsymmetric case, it could be a reasonable approach if all you want to do is position text (which doesn't require mathematical precision). – John Coleman Jan 16 '19 at 13:58