aab29 / bezier.dart

A 2D Bézier curve math library written in Dart
BSD 2-Clause "Simplified" License
54 stars 9 forks source link

Awesome Library, can you convert to swift ? #17

Open FlashTang opened 4 years ago

FlashTang commented 4 years ago

Thank you for writing this awesome library , but I don't know Dart , any chance to convert this library to apple Swift ? I want to realize such line effect : (Draw with Adobe Flash CC Pen Tool , single line but with tapered width effect) BezierLineByAdobeFlashCC At first, I tried to use 2 Cubic Bezier Curves, but seems it's not so simple (I have no idea how to adjust that 4 control points, and even I don't know that if this is possible) so now I'm trying to use single curves , and split it to segments (same length) ,and draw those segments with different width from big to small (maybe bad performance ? since the line(s) will be animated , any suggest ? )

Pomax commented 4 years ago

At first, I tried to use 2 Cubic Bezier Curves, but seems it's not so simple (I have no idea how to adjust that 4 control points, and even I don't know that if this is possible)

it's not.

FlashTang commented 4 years ago

At first, I tried to use 2 Cubic Bezier Curves, but seems it's not so simple (I have no idea how to adjust that 4 control points, and even I don't know that if this is possible)

it's not.

Hi Pomax , actually I found your bezierjs project & readed that 「§39 Curve offsetting」article before I noticed your reply. The "Graduated curve offsetting" is exactly what I want, I think I can grab some relevant codes from bezierjs then convert to swift , or maybe use bezierjs to get "bezier data" on swift directly (use "JavaScriptCore" as bridge) , or use wkwebview for rendering bezier lines singly (some as I using LaTex - MathJax js on swift ) Thanks for your great project and the free book, it's fun to read !

FlashTang commented 4 years ago

@aab29 @Pomax Hi ,I tried JavaScriptCore + ios , but slow performance ( I guess only 5 fps animated curves ) So I port it to swift, bezierjs based : https://github.com/FlashTang/BezierSwift But still slow performance ( I mean the offset function) ,it seems ok if you have only 1 or 2 offset curves , but if you have more offset curves (e.g 4 curves), it's getting slow, very low , let alone 10 or 30 offset curves p.s I also converted bezier.dart to swift , the same result (a little bit better than the port based on bezierjs) So, I suspect there are something wrong in my code then I back to HTML + Canvas + bezierjs , but it acts the same ,slow ,logy
I don't know if this is proleptic (since offset processing is heavy ? ) , thank you There is the code index.js

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
function draw(event){
    var p = getMousePos(c, event);
    ctx.clearRect(0,0,c.width, c.height);
    var bezier = new Bezier({x:p.x,y:p.y},{x:50,y:50},{x:200,y:50},{x:200,y:200});
    var points = bezier.points;
    ctx.beginPath();
    var i;
    for(i=0;i<4;i++){ // if change to i < 1 , works smoothly
        var offsetBeziers = bezier.offset(i * 10);
        offsetBeziers.forEach(function(bz){
            points = bz.points;
            ctx.moveTo(points[0].x, points[0].y);
            ctx.bezierCurveTo(points[1].x,points[1].y, points[2].x, points[2].y, points[3].x, points[3].y);
        })
    }
    ctx.stroke();
}

function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    };
}

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Bezierjs Test</title>
</head>
<body>
  <h1>Bezierjs Test</h1>

  <canvas onmousemove="draw(event)" id="myCanvas" width="640" height="480" style="border:1px solid #000000;"></canvas>

  <script src="./bezier.js"></script>
  <script src="./index.js"></script>

</body>
</html>
Pomax commented 4 years ago

Perhaps https://stackoverflow.com/a/18017438 is useful to you?

FlashTang commented 4 years ago

Perhaps https://stackoverflow.com/a/18017438 is useful to you? Hi Pomax thanks for the link, actually I had the same idea in the pinned answer of this link early, I guess maybe it will perform the same - aka slow , anyway I will give it try Besides, I found a small logical mistake ? in your bezierjs - utils.js - compute function At line 164 dCpts[i].z is always "undefined" ,since dCpts[i] = {x:..,y:...}

// higher order curves: use de Casteljau's computation
      var dCpts = JSON.parse(JSON.stringify(points));
      while (dCpts.length > 1) {
        for (var i = 0; i < dCpts.length - 1; i++) {
          dCpts[i] = {
            x: dCpts[i].x + (dCpts[i + 1].x - dCpts[i].x) * t,
            y: dCpts[i].y + (dCpts[i + 1].y - dCpts[i].y) * t
          };
          if (typeof dCpts[i].z !== "undefined") {
            dCpts[i] = dCpts[i].z + (dCpts[i + 1].z - dCpts[i].z) * t;
          }
        }
        dCpts.splice(dCpts.length - 1, 1);
      }
FlashTang commented 4 years ago

Perhaps https://stackoverflow.com/a/18017438 is useful to you?

Just tested this idea , it's fast , fairly fast even with 100 curves , but unfortunately ,it's not "safe" ,it can get a convolution Screen Shot 2020-09-25 at 7 30 15 PM

BUT fortunately , it works fine if the distance is small ,for my use the distance is small ,and the angle always less than 90 Screen Shot 2020-09-25 at 7 44 34 PM

Thanks agian, very appreciated your help

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
function draw(event){ 

    var p = getMousePos(c, event);
    ctx.clearRect(0,0,c.width, c.height);
    var bezier = new Bezier({x:c.width/2,y:400},{x:50,y:50},{x:200,y:50},{x:p.x,y:p.y});
    ctx.beginPath();
    var pt, nv, d=50;
    var pts_nvs = [],i,j;
    for(var t=0; t<=1; t+=0.01) {
        var pt = bezier.get(t);
        var nv = bezier.normal(t);
        pts_nvs.push({pt:pt,nv:nv,t:t});
    }
    for(i=-3;i<3;i++){
        for(j=0;j<pts_nvs.length;j++){
            var m = 1 - pts_nvs[j].t
            if(j==0){
                ctx.moveTo(bezier.points[0].x + pts_nvs[j].nv.x * d * i * m,bezier.points[0].y + pts_nvs[j].nv.y * d * i * m);
            }
            else{
                ctx.lineTo(pts_nvs[j].pt.x + pts_nvs[j].nv.x * d * i * m,pts_nvs[j].pt.y + pts_nvs[j].nv.y * d * i * m);
            }
        }
    } 
    ctx.stroke();

}

function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    };
}
Pomax commented 4 years ago

Besides, I found a small logical mistake ? in your bezierjs - utils.js - compute function

please file that over on https://github.com/pomax/bezierjs because I'm guaranteed going to forget about it otherwise ^^;

FlashTang commented 4 years ago

otherwise

^Done,just created an issue https://github.com/Pomax/bezierjs/issues/134