简体   繁体   中英

Making a sine wave curve around a path in javascript

I am trying to figure out a nice way to make a sine wave flow naturally along a javascript path. I made something like this:

在此处输入图片说明

Which captures some of the intent but it's very forced and unnatural, especially around the change direction. I also would love to accommodate for higher slope, but not sure if that ives a more natural effect or not.

Any thoughts on how I might be able to accomplish this?

The intent was:

1) Take a set of points

2) Break into equal segments

3) Adjust the actual line's position by the difference of the sin coords and the actual line coords.

This gives a pretty weak display though, and I'd like to create something that was more natural and flowing as if to capture the flow of a sine wave travelling along a path.

var c = document.getElementById("c");
var ctx = c.getContext("2d");
var cw = c.width = window.innerWidth;
var ch = c.height = window.innerHeight;
var cx = cw / 2,
  cy = ch / 2;
var rad = Math.PI / 180;
var w = cw;
var h = ch * 0.3;
var amplitude = h;
var frequency = 0.01;
var phi = 0;
var frames = 0;
var stopped = true;
ctx.lineWidth = .4;

var offset = 100;

var points = interpolateLineRange( [ [0, 0], [ 95, 58], [84, 158], [350, 300], [540, 190] ], 20);
points = interpolateLineRange(points, 100);

ctx.moveTo(0, 0);
var distance_traveled = 0;
var current_slope = 0;

for (var ii in points) {

  if (ii == 0) {
    continue;
  }
  distance_traveled += dist(points[ii - 1], points[ii]);
  current_slope = slope(points[ii - 1], points[ii]);

  var newY = Math.sin(distance_traveled * .07) * 45 + points[ii][1];
  var diff = newY - points[ii][1];

  if (points[ii][1] > points[ii - 1][1]) {
    ctx.lineTo(points[ii][0] - diff, newY);
  } else {
    ctx.lineTo(points[ii][0] + diff, newY);
  }
}

ctx.stroke();
ctx.moveTo(0, 0);

for (var ii in points) {
  ctx.lineTo(points[ii][0], points[ii][1]);
}
ctx.strokeStyle = 'red';
ctx.stroke();

The problem isn't really "drawing sine waves along a path": that part is actually trivial. Take your path section, express it in terms of a distance or time variable, and then draw the sines (or anything else) as an offset function:

for t=0; t<distance; t+=fraction of distance:
  point = path.get(t)
  normal = path.normal(t)
  strength = sin(t)
  if t=0:
    ctx.moveTo(point + strength * normal)
  else: 
    ctx.lineTo(point + strength * normal)

Easy enough, let's implement that: http://jsbin.com/nefemazovo/edit?js,output

Sure, it's a bit of code, but it's hardly complicated: just a class that models a polygonal path that tracks its length as we add points to it, and a draw function that draws the polygon, as well as some offset function, by sampling the polygon at regular intervals and computing the normal at each point.

The real question is: how are you going to deal with overlaps in your offset data? For instance, from the example above:

在此处输入图片说明

There's a pretty obvious area here where we're going to have to do ... something:

在此处输入图片说明

So what do we do? Turns out: no one knows, that's really up to you. For instance, you could draw "uneven" sines so that you always end up with a node at the end points of your polygonal sections. Might work, but you might also still have overlap if there's a small enough angle between consecutive segments. Plus your sines would be uneven, so would that look good? Ehh... up to you. Or, you could dampen the offset strength to zero at the polygon transition, and then ramp it back up to 100%, but will that look good? No idea, that is your call. You could also use interpolation so that the sine waves "blend" at the transition. Will that look good? Again, no idea, still up to you. You could even replace the offending section of polygon with something like a quadratic or cubic curve, so you always have smooth transitions along which sine offsets will "just work", but will that look good? ...you get the idea =)

The part of this question we can answer isn't super interesting, and the part that's interesting we unfortunately cannot answer for you...

We can give advice, though: I don't know what your polygon represents, but "curves" almost always work better as spines (almost, because curves can have discontinuities as well, which is the very thing you want to avoid), so if you can construct curves instead, probably worth it. However, that won't solve the problem of weird overlaps when your angles are too small:

在此处输入图片说明

You're still left with problems that can only be solved with "executive decisions" more than textbook "in this situation, do this: ..." solutions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM