From de0600e1e2a0fa4e666e7c49c772379a29ffeba9 Mon Sep 17 00:00:00 2001 From: treeform Date: Wed, 29 Jun 2022 22:49:28 -0700 Subject: [PATCH 1/2] Cubic tangent error. --- src/pixie/paths.nim | 25 ++++++++++++++++++++----- tests/test_path2.nim | 12 ++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 tests/test_path2.nim diff --git a/src/pixie/paths.nim b/src/pixie/paths.nim index 4cb2fa5..9739a2f 100644 --- a/src/pixie/paths.nim +++ b/src/pixie/paths.nim @@ -675,10 +675,21 @@ proc commandsToShapes( proc addCubic(shape: var Polygon, at, ctrl1, ctrl2, to: Vec2) = ## Adds cubic segments to shape. proc compute(at, ctrl1, ctrl2, to: Vec2, t: float32): Vec2 {.inline.} = - pow(1 - t, 3) * at + - pow(1 - t, 2) * 3 * t * ctrl1 + - (1 - t) * 3 * pow(t, 2) * ctrl2 + - pow(t, 3) * to + let + t2 = t*t + t3 = t2*t + at * (-t3 + 3*t2 - 3*t + 1) + + ctrl1 * (3*t3 - 6*t2 + 3*t) + + ctrl2 * (-3*t3 + 3*t2) + + to * (t3) + + proc computeDerv(at, ctrl1, ctrl2, to: Vec2, t: float32): Vec2 {.inline.} = + let + t2 = t*t + at * (-3*t2 + 6*t - 3) + + ctrl1 * (9*t2 - 12*t + 3) + + ctrl2 * (-9*t2 + 6*t) + + to * (3 * t2) var t: float32 # Where we are at on the curve from [0, 1] @@ -691,7 +702,11 @@ proc commandsToShapes( raise newException(PixieError, "Unable to discretize cubic") let midpoint = (prev + next) / 2 - error = (midpoint - halfway).lengthSq + lineTangent = midpoint - prev + curveTangent = computeDerv(at, ctrl1, ctrl2, to, t + step / 2) + curveTangentScaled = curveTangent.normalize() * lineTangent.length() + error = (midpoint - halfway).lengthSq + + (lineTangent - curveTangentScaled).lengthSq if error > errorMarginSq: next = halfway halfway = compute(at, ctrl1, ctrl2, to, t + step / 4) diff --git a/tests/test_path2.nim b/tests/test_path2.nim new file mode 100644 index 0000000..bc6f70a --- /dev/null +++ b/tests/test_path2.nim @@ -0,0 +1,12 @@ +import chroma, pixie, pixie/fileformats/png, strformat + +block: + let + image = newImage(100, 100) + pathStr = """ + M 40 40 L 40 80 L 80 80 L 80 40 C 80 -20 40 100 40 40 + """ + color = rgba(0, 0, 0, 255) + image.fill(rgba(255, 255, 255, 255)) + image.fillPath(pathStr, color) + image.writeFile("tests/paths/pathSwish.png") From 04abf707fa07795bbb226e9032ce868ce55aa726 Mon Sep 17 00:00:00 2001 From: treeform Date: Wed, 29 Jun 2022 23:14:34 -0700 Subject: [PATCH 2/2] Cleanup. --- src/pixie/paths.nim | 13 ++++++------- tests/paths/pathSwish.png | Bin 0 -> 964 bytes tests/test_path2.nim | 12 ------------ tests/test_paths.nim | 11 +++++++++++ 4 files changed, 17 insertions(+), 19 deletions(-) create mode 100644 tests/paths/pathSwish.png delete mode 100644 tests/test_path2.nim diff --git a/src/pixie/paths.nim b/src/pixie/paths.nim index 9739a2f..4719508 100644 --- a/src/pixie/paths.nim +++ b/src/pixie/paths.nim @@ -683,9 +683,8 @@ proc commandsToShapes( ctrl2 * (-3*t3 + 3*t2) + to * (t3) - proc computeDerv(at, ctrl1, ctrl2, to: Vec2, t: float32): Vec2 {.inline.} = - let - t2 = t*t + proc computeDeriv(at, ctrl1, ctrl2, to: Vec2, t: float32): Vec2 {.inline.} = + let t2 = t*t at * (-3*t2 + 6*t - 3) + ctrl1 * (9*t2 - 12*t + 3) + ctrl2 * (-9*t2 + 6*t) + @@ -703,11 +702,11 @@ proc commandsToShapes( let midpoint = (prev + next) / 2 lineTangent = midpoint - prev - curveTangent = computeDerv(at, ctrl1, ctrl2, to, t + step / 2) + curveTangent = computeDeriv(at, ctrl1, ctrl2, to, t + step / 2) curveTangentScaled = curveTangent.normalize() * lineTangent.length() - error = (midpoint - halfway).lengthSq + - (lineTangent - curveTangentScaled).lengthSq - if error > errorMarginSq: + error = (midpoint - halfway).lengthSq + errorTangent = (lineTangent - curveTangentScaled).lengthSq + if error + errorTangent > errorMarginSq: next = halfway halfway = compute(at, ctrl1, ctrl2, to, t + step / 4) step /= 2 diff --git a/tests/paths/pathSwish.png b/tests/paths/pathSwish.png new file mode 100644 index 0000000000000000000000000000000000000000..a58993ca72a96e553c9deb428dc22a6c71cb8ffb GIT binary patch literal 964 zcmeAS@N?(olHy`uVBq!ia0vp^DImj_>z{Aw$cz~cFOG!iK zRzE+#CF|GwbG15E&h+K^)Vg%3YG!8U#NE4h`)9v-^X9~(M~{|2H8b!KjgF4Kbn~X> z`t|EW|NRngzH;*C&z)PgZ$JI`@#6Q!&x&@+Tjmtb``_aaGBod*J#QXgZQPB!cWdw8l4BG6$X1q<<5SP` z^uq^(E596F>^k;MdiCzzwCU5QD?I*s@afa1?e}v#Y9@4ca^Adm&rHgjZKKZYv!|Xs zS@Lo5zazh+Cf;=}F%a%-DdhS3;lqOaYr1kKT)Y@)X=}SS)8PKSds(;k&GKOLTpDC# zY#f|x<8<=*=Y`k!m5LnKty`B;P+)N4Moo8h2kYU(hl>ge6CX}&am?DfVS~cw&!4y2 z`9yAv(D|Rk{YUZiwZf?Nl5K5mIlZ_08~Kx7Ti6;HJeX^L!By$Rn>TB|pE||*!7Bu$7!WYu2nuK5EIkey(reUnE|n z_T|~dA3t`ST(+OfuH&TKqVE>FcJ12peqAH~B4hT$mu#KC3y2?N=d|AN>)671)-kN| zDf#*OA8zF3yKOgf@S;W z&Bpt$&S8*ud0F{T`&XCO^M`qPd39U6g6D7;nVUbC-Sw}uzFvRr+O_vmTK~5SJAV1Q z=H9(~{Ou}xnXaGD)6v)eudi$4#}fFf(1>@z{G?0%#xE_EPb|r}ZXxUv8y{bt=%XhV z`!HmJMgp{l