More path tests.

This commit is contained in:
treeform 2020-12-02 23:25:24 -08:00
parent df424b7635
commit 3ae54dad41
3 changed files with 33 additions and 58 deletions

View file

@ -173,15 +173,15 @@ type ArcParams = object
theta, delta: float32
proc svgAngle (ux, uy, vx, vy: float32): float32 =
var u = vec2(ux, uy);
var v = vec2(vx, vy);
var u = vec2(ux, uy)
var v = vec2(vx, vy)
# (F.6.5.4)
var dot = dot(u,v);
var len = length(u) * length(v);
var ang = arccos( clamp(dot / len,-1,1) ); # floating point precision, slightly over values appear
var dot = dot(u,v)
var len = length(u) * length(v)
var ang = arccos( clamp(dot / len,-1,1) ) # floating point precision, slightly over values appear
if (u.x*v.y - u.y*v.x) < 0:
ang = -ang
return ang;
return ang
proc endpointToCenterArcParams(
ax, ay, rx, ry, rotation, large, sweep, bx, by: float32
@ -199,48 +199,48 @@ proc endpointToCenterArcParams(
# (F.6.5.1)
var dx2 = (p1.x - p2.x) / 2.0
var dy2 = (p1.y - p2.y) / 2.0
var x1p = cos(xAngle)*dx2 + sin(xAngle)*dy2;
var y1p = -sin(xAngle)*dx2 + cos(xAngle)*dy2;
var x1p = cos(xAngle)*dx2 + sin(xAngle)*dy2
var y1p = -sin(xAngle)*dx2 + cos(xAngle)*dy2
# (F.6.5.2)
var rxs = rX * rX;
var rys = rY * rY;
var x1ps = x1p * x1p;
var y1ps = y1p * y1p;
var rxs = rX * rX
var rys = rY * rY
var x1ps = x1p * x1p
var y1ps = y1p * y1p
# check if the radius is too small `pq < 0`, when `dq > rxs * rys` (see below)
# cr is the ratio (dq : rxs * rys)
var cr = x1ps/rxs + y1ps/rys;
var cr = x1ps/rxs + y1ps/rys
var s = 1.0
if cr > 1:
# scale up rX,rY equally so cr == 1
s = sqrt(cr);
rX = s * rX;
rY = s * rY;
rxs = rX * rX;
rys = rY * rY;
s = sqrt(cr)
rX = s * rX
rY = s * rY
rxs = rX * rX
rys = rY * rY
var dq = (rxs * y1ps + rys * x1ps);
var pq = (rxs*rys - dq) / dq;
var q = sqrt(max(0,pq)); # use Max to account for float precision
var dq = (rxs * y1ps + rys * x1ps)
var pq = (rxs*rys - dq) / dq
var q = sqrt(max(0,pq)) # use Max to account for float precision
if flagA == flagS:
q = -q;
var cxp = q * rX * y1p / rY;
var cyp = - q * rY * x1p / rX;
q = -q
var cxp = q * rX * y1p / rY
var cyp = - q * rY * x1p / rX
# (F.6.5.3)
var cx = cos(xAngle)*cxp - sin(xAngle)*cyp + (p1.x + p2.x)/2;
var cy = sin(xAngle)*cxp + cos(xAngle)*cyp + (p1.y + p2.y)/2;
var cx = cos(xAngle)*cxp - sin(xAngle)*cyp + (p1.x + p2.x)/2
var cy = sin(xAngle)*cxp + cos(xAngle)*cyp + (p1.y + p2.y)/2
# (F.6.5.5)
var theta = svgAngle( 1,0, (x1p-cxp) / rX, (y1p - cyp)/rY );
var theta = svgAngle( 1,0, (x1p-cxp) / rX, (y1p - cyp)/rY )
# (F.6.5.6)
var delta = svgAngle(
(x1p - cxp)/rX, (y1p - cyp)/rY,
(-x1p - cxp)/rX, (-y1p-cyp)/rY);
(-x1p - cxp)/rX, (-y1p-cyp)/rY)
delta = delta mod (PI * 2)
if not flagS:
delta -= 2 * PI;
delta -= 2 * PI
# normalize the delta
while delta > PI*2:
@ -248,7 +248,7 @@ proc endpointToCenterArcParams(
while delta < -PI*2:
delta += PI*2
r = vec2(rX, rY);
r = vec2(rX, rY)
return ArcParams(
s: s, rx: rX, rY: ry, rotation: xAngle, cx: cx, cy: cy,
@ -388,7 +388,6 @@ proc commandsToPolygons*(commands: seq[PathCommand]): seq[seq[Vec2]] =
var a = arc.theta
var rotMat = rotationMat3(-arc.rotation)
for i in 0 .. steps:
# polygon.add(polygon[^1])
polygon.add(rotMat * vec2(
cos(a)*arc.rx,
sin(a)*arc.ry) + vec2(arc.cx, arc.cy)
@ -505,10 +504,8 @@ proc strokePolygons*(ps: seq[seq[Vec2]], strokeWidthR, strokeWidthL: float32): s
var prevLSeg: Segment
var first = true
for (at, to) in p.zipline:
#echo at, ":", to
let tangent = (at - to).normalize()
let normal = vec2(-tangent.y, tangent.x)
#print tangent, normal
var
rSeg = segment(at + normal * strokeWidthR, to + normal * strokeWidthR)
@ -518,7 +515,6 @@ proc strokePolygons*(ps: seq[seq[Vec2]], strokeWidthR, strokeWidthL: float32): s
first = false
# TODO: draw start cap
else:
# as previous lines
var touch: Vec2
if intersects(prevRSeg, rSeg, touch):
rSeg.at = touch
@ -669,6 +665,7 @@ proc strokePath*(
path: Path,
color: ColorRGBA,
strokeWidth: float32 = 1.0,
# TODO: Add more params:
# strokeLocation: StrokeLocation,
# strokeCap: StorkeCap,
# strokeJoin: StorkeJoin
@ -764,15 +761,10 @@ proc arcTo*(path: Path, x1, y1, x2, y2, r: float32) =
const epsilon: float32 = 1e-6
# if x1 != path.at.x or y1 != path.at.y:
# path.commands.add(PathCommand(kind: Line, numbers: @[x1, y1]))
# path.at.x = x1
# path.at.y = y1
var r = r
if r < 0:
# Is the radius negative? Error.
# Is the radius negative? Flip it.
r = -r
#raise newException(ValueError, "negative radius: " & $r)
if path.commands.len == 0:
# Is this path empty? Move to (x1,y1).
@ -787,7 +779,6 @@ proc arcTo*(path: Path, x1, y1, x2, y2, r: float32) =
# // Equivalently, is (x1,y1) coincident with (x2,y2)?
# // Or, is the radius zero? Line to (x1,y1).
#this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1);
path.commands.add(PathCommand(kind: Line, numbers: @[x1, y1]))
path.at.x = x1
path.at.y = y1
@ -807,12 +798,8 @@ proc arcTo*(path: Path, x1, y1, x2, y2, r: float32) =
# If the start tangent is not coincident with (x0,y0), line to.
if abs(t01 - 1) > epsilon:
#this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01)
path.commands.add(PathCommand(kind: Line, numbers: @[x1 + t01 * x01, y1 + t01 * y01]))
discard
# this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21);
path.at.x = x1 + t21 * x21
path.at.y = y1 + t21 * y21
path.commands.add(PathCommand(

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,12 +1,10 @@
import pixie, chroma
block:
echo "pathNumbers"
let pathStr = "M 0.1E-10 0.1e10 L2+2 L3-3 L0.1E+10-1"
let path = parsePath(pathStr)
block:
echo "pathStroke1"
let image = newImage(100, 100)
let pathStr = "M 10 10 L 90 90"
let color = rgba(255, 0, 0, 255)
@ -14,7 +12,6 @@ block:
image.writeFile("tests/images/pathStroke1.png")
block:
echo "pathStroke2"
let image = newImage(100, 100)
let pathStr = "M 10 10 L 50 60 90 90"
let color = rgba(255, 0, 0, 255)
@ -22,7 +19,6 @@ block:
image.writeFile("tests/images/pathStroke2.png")
block:
echo "pathStroke3"
let image = newImage(100, 100)
image.strokePath(
"M 15 10 L 30 90 60 30 90 90",
@ -32,7 +28,6 @@ block:
image.writeFile("tests/images/pathStroke3.png")
block:
echo "pathBlackRectangle"
let image = newImage(100, 100)
let pathStr = "M 10 10 H 90 V 90 H 10 L 10 10"
let color = rgba(0, 0, 0, 255)
@ -40,7 +35,6 @@ block:
image.writeFile("tests/images/pathBlackRectangle.png")
block:
echo "pathYellowRectangle"
let image = newImage(100, 100)
image.fillPath(
"M 10 10 H 90 V 90 H 10 L 10 10",
@ -49,7 +43,6 @@ block:
image.writeFile("tests/images/pathYellowRectangle.png")
block:
echo "pathRedRectangle"
let image = newImage(100, 100)
var path = newPath()
path.moveTo(10, 10)
@ -64,16 +57,14 @@ block:
image.writeFile("tests/images/pathRedRectangle.png")
block:
echo "pathBottomArc"
let image = newImage(100, 100)
image.fillPath(
"M30 60 A 20 20 0 0 0 90 60 L 30 60",
parseHtmlColor("#FC427B").rgba
)
image.writeFile("pathBottomArc.png")
image.writeFile("tests/images/pathBottomArc.png")
block:
echo "pathHeart"
let image = newImage(100, 100)
image.fillPath(
"""
@ -88,7 +79,6 @@ block:
image.writeFile("tests/images/pathHeart.png")
block:
echo "pathRotatedArc"
let image = newImage(100, 100)
image.fillPath(
"M 20 50 A 20 10 45 1 1 80 50 L 20 50",
@ -97,7 +87,6 @@ block:
image.writeFile("tests/images/pathRotatedArc.png")
block:
echo "pathInvertedCornerArc"
let image = newImage(100, 100)
image.fillPath(
"M 0 50 A 50 50 0 0 0 50 0 L 50 50 L 0 50",
@ -106,7 +95,6 @@ block:
image.writeFile("tests/images/pathInvertedCornerArc.png")
block:
echo "pathCornerArc"
let image = newImage(100, 100)
image.fillPath(
"M 0 50 A 50 50 0 0 1 50 0 L 50 50 L 0 50",