More path tests.
This commit is contained in:
parent
df424b7635
commit
3ae54dad41
3 changed files with 33 additions and 58 deletions
|
@ -173,15 +173,15 @@ type ArcParams = object
|
||||||
theta, delta: float32
|
theta, delta: float32
|
||||||
|
|
||||||
proc svgAngle (ux, uy, vx, vy: float32): float32 =
|
proc svgAngle (ux, uy, vx, vy: float32): float32 =
|
||||||
var u = vec2(ux, uy);
|
var u = vec2(ux, uy)
|
||||||
var v = vec2(vx, vy);
|
var v = vec2(vx, vy)
|
||||||
# (F.6.5.4)
|
# (F.6.5.4)
|
||||||
var dot = dot(u,v);
|
var dot = dot(u,v)
|
||||||
var len = length(u) * length(v);
|
var len = length(u) * length(v)
|
||||||
var ang = arccos( clamp(dot / len,-1,1) ); # floating point precision, slightly over values appear
|
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:
|
if (u.x*v.y - u.y*v.x) < 0:
|
||||||
ang = -ang
|
ang = -ang
|
||||||
return ang;
|
return ang
|
||||||
|
|
||||||
proc endpointToCenterArcParams(
|
proc endpointToCenterArcParams(
|
||||||
ax, ay, rx, ry, rotation, large, sweep, bx, by: float32
|
ax, ay, rx, ry, rotation, large, sweep, bx, by: float32
|
||||||
|
@ -199,48 +199,48 @@ proc endpointToCenterArcParams(
|
||||||
# (F.6.5.1)
|
# (F.6.5.1)
|
||||||
var dx2 = (p1.x - p2.x) / 2.0
|
var dx2 = (p1.x - p2.x) / 2.0
|
||||||
var dy2 = (p1.y - p2.y) / 2.0
|
var dy2 = (p1.y - p2.y) / 2.0
|
||||||
var x1p = cos(xAngle)*dx2 + sin(xAngle)*dy2;
|
var x1p = cos(xAngle)*dx2 + sin(xAngle)*dy2
|
||||||
var y1p = -sin(xAngle)*dx2 + cos(xAngle)*dy2;
|
var y1p = -sin(xAngle)*dx2 + cos(xAngle)*dy2
|
||||||
|
|
||||||
# (F.6.5.2)
|
# (F.6.5.2)
|
||||||
var rxs = rX * rX;
|
var rxs = rX * rX
|
||||||
var rys = rY * rY;
|
var rys = rY * rY
|
||||||
var x1ps = x1p * x1p;
|
var x1ps = x1p * x1p
|
||||||
var y1ps = y1p * y1p;
|
var y1ps = y1p * y1p
|
||||||
# check if the radius is too small `pq < 0`, when `dq > rxs * rys` (see below)
|
# check if the radius is too small `pq < 0`, when `dq > rxs * rys` (see below)
|
||||||
# cr is the ratio (dq : rxs * rys)
|
# cr is the ratio (dq : rxs * rys)
|
||||||
var cr = x1ps/rxs + y1ps/rys;
|
var cr = x1ps/rxs + y1ps/rys
|
||||||
var s = 1.0
|
var s = 1.0
|
||||||
if cr > 1:
|
if cr > 1:
|
||||||
# scale up rX,rY equally so cr == 1
|
# scale up rX,rY equally so cr == 1
|
||||||
s = sqrt(cr);
|
s = sqrt(cr)
|
||||||
rX = s * rX;
|
rX = s * rX
|
||||||
rY = s * rY;
|
rY = s * rY
|
||||||
rxs = rX * rX;
|
rxs = rX * rX
|
||||||
rys = rY * rY;
|
rys = rY * rY
|
||||||
|
|
||||||
var dq = (rxs * y1ps + rys * x1ps);
|
var dq = (rxs * y1ps + rys * x1ps)
|
||||||
var pq = (rxs*rys - dq) / dq;
|
var pq = (rxs*rys - dq) / dq
|
||||||
var q = sqrt(max(0,pq)); # use Max to account for float precision
|
var q = sqrt(max(0,pq)) # use Max to account for float precision
|
||||||
if flagA == flagS:
|
if flagA == flagS:
|
||||||
q = -q;
|
q = -q
|
||||||
var cxp = q * rX * y1p / rY;
|
var cxp = q * rX * y1p / rY
|
||||||
var cyp = - q * rY * x1p / rX;
|
var cyp = - q * rY * x1p / rX
|
||||||
|
|
||||||
# (F.6.5.3)
|
# (F.6.5.3)
|
||||||
var cx = cos(xAngle)*cxp - sin(xAngle)*cyp + (p1.x + p2.x)/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;
|
var cy = sin(xAngle)*cxp + cos(xAngle)*cyp + (p1.y + p2.y)/2
|
||||||
|
|
||||||
# (F.6.5.5)
|
# (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)
|
# (F.6.5.6)
|
||||||
var delta = svgAngle(
|
var delta = svgAngle(
|
||||||
(x1p - cxp)/rX, (y1p - cyp)/rY,
|
(x1p - cxp)/rX, (y1p - cyp)/rY,
|
||||||
(-x1p - cxp)/rX, (-y1p-cyp)/rY);
|
(-x1p - cxp)/rX, (-y1p-cyp)/rY)
|
||||||
delta = delta mod (PI * 2)
|
delta = delta mod (PI * 2)
|
||||||
|
|
||||||
if not flagS:
|
if not flagS:
|
||||||
delta -= 2 * PI;
|
delta -= 2 * PI
|
||||||
|
|
||||||
# normalize the delta
|
# normalize the delta
|
||||||
while delta > PI*2:
|
while delta > PI*2:
|
||||||
|
@ -248,7 +248,7 @@ proc endpointToCenterArcParams(
|
||||||
while delta < -PI*2:
|
while delta < -PI*2:
|
||||||
delta += PI*2
|
delta += PI*2
|
||||||
|
|
||||||
r = vec2(rX, rY);
|
r = vec2(rX, rY)
|
||||||
|
|
||||||
return ArcParams(
|
return ArcParams(
|
||||||
s: s, rx: rX, rY: ry, rotation: xAngle, cx: cx, cy: cy,
|
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 a = arc.theta
|
||||||
var rotMat = rotationMat3(-arc.rotation)
|
var rotMat = rotationMat3(-arc.rotation)
|
||||||
for i in 0 .. steps:
|
for i in 0 .. steps:
|
||||||
# polygon.add(polygon[^1])
|
|
||||||
polygon.add(rotMat * vec2(
|
polygon.add(rotMat * vec2(
|
||||||
cos(a)*arc.rx,
|
cos(a)*arc.rx,
|
||||||
sin(a)*arc.ry) + vec2(arc.cx, arc.cy)
|
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 prevLSeg: Segment
|
||||||
var first = true
|
var first = true
|
||||||
for (at, to) in p.zipline:
|
for (at, to) in p.zipline:
|
||||||
#echo at, ":", to
|
|
||||||
let tangent = (at - to).normalize()
|
let tangent = (at - to).normalize()
|
||||||
let normal = vec2(-tangent.y, tangent.x)
|
let normal = vec2(-tangent.y, tangent.x)
|
||||||
#print tangent, normal
|
|
||||||
|
|
||||||
var
|
var
|
||||||
rSeg = segment(at + normal * strokeWidthR, to + normal * strokeWidthR)
|
rSeg = segment(at + normal * strokeWidthR, to + normal * strokeWidthR)
|
||||||
|
@ -518,7 +515,6 @@ proc strokePolygons*(ps: seq[seq[Vec2]], strokeWidthR, strokeWidthL: float32): s
|
||||||
first = false
|
first = false
|
||||||
# TODO: draw start cap
|
# TODO: draw start cap
|
||||||
else:
|
else:
|
||||||
# as previous lines
|
|
||||||
var touch: Vec2
|
var touch: Vec2
|
||||||
if intersects(prevRSeg, rSeg, touch):
|
if intersects(prevRSeg, rSeg, touch):
|
||||||
rSeg.at = touch
|
rSeg.at = touch
|
||||||
|
@ -669,6 +665,7 @@ proc strokePath*(
|
||||||
path: Path,
|
path: Path,
|
||||||
color: ColorRGBA,
|
color: ColorRGBA,
|
||||||
strokeWidth: float32 = 1.0,
|
strokeWidth: float32 = 1.0,
|
||||||
|
# TODO: Add more params:
|
||||||
# strokeLocation: StrokeLocation,
|
# strokeLocation: StrokeLocation,
|
||||||
# strokeCap: StorkeCap,
|
# strokeCap: StorkeCap,
|
||||||
# strokeJoin: StorkeJoin
|
# strokeJoin: StorkeJoin
|
||||||
|
@ -764,15 +761,10 @@ proc arcTo*(path: Path, x1, y1, x2, y2, r: float32) =
|
||||||
|
|
||||||
const epsilon: float32 = 1e-6
|
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
|
var r = r
|
||||||
if r < 0:
|
if r < 0:
|
||||||
# Is the radius negative? Error.
|
# Is the radius negative? Flip it.
|
||||||
r = -r
|
r = -r
|
||||||
#raise newException(ValueError, "negative radius: " & $r)
|
|
||||||
|
|
||||||
if path.commands.len == 0:
|
if path.commands.len == 0:
|
||||||
# Is this path empty? Move to (x1,y1).
|
# 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)?
|
# // Equivalently, is (x1,y1) coincident with (x2,y2)?
|
||||||
# // Or, is the radius zero? Line to (x1,y1).
|
# // 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.commands.add(PathCommand(kind: Line, numbers: @[x1, y1]))
|
||||||
path.at.x = x1
|
path.at.x = x1
|
||||||
path.at.y = y1
|
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 the start tangent is not coincident with (x0,y0), line to.
|
||||||
if abs(t01 - 1) > epsilon:
|
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]))
|
path.commands.add(PathCommand(kind: Line, numbers: @[x1 + t01 * x01, y1 + t01 * y01]))
|
||||||
discard
|
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.x = x1 + t21 * x21
|
||||||
path.at.y = y1 + t21 * y21
|
path.at.y = y1 + t21 * y21
|
||||||
path.commands.add(PathCommand(
|
path.commands.add(PathCommand(
|
||||||
|
|
BIN
tests/images/pathBottomArc.png
Normal file
BIN
tests/images/pathBottomArc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -1,12 +1,10 @@
|
||||||
import pixie, chroma
|
import pixie, chroma
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathNumbers"
|
|
||||||
let pathStr = "M 0.1E-10 0.1e10 L2+2 L3-3 L0.1E+10-1"
|
let pathStr = "M 0.1E-10 0.1e10 L2+2 L3-3 L0.1E+10-1"
|
||||||
let path = parsePath(pathStr)
|
let path = parsePath(pathStr)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathStroke1"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
let pathStr = "M 10 10 L 90 90"
|
let pathStr = "M 10 10 L 90 90"
|
||||||
let color = rgba(255, 0, 0, 255)
|
let color = rgba(255, 0, 0, 255)
|
||||||
|
@ -14,7 +12,6 @@ block:
|
||||||
image.writeFile("tests/images/pathStroke1.png")
|
image.writeFile("tests/images/pathStroke1.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathStroke2"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
let pathStr = "M 10 10 L 50 60 90 90"
|
let pathStr = "M 10 10 L 50 60 90 90"
|
||||||
let color = rgba(255, 0, 0, 255)
|
let color = rgba(255, 0, 0, 255)
|
||||||
|
@ -22,7 +19,6 @@ block:
|
||||||
image.writeFile("tests/images/pathStroke2.png")
|
image.writeFile("tests/images/pathStroke2.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathStroke3"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
image.strokePath(
|
image.strokePath(
|
||||||
"M 15 10 L 30 90 60 30 90 90",
|
"M 15 10 L 30 90 60 30 90 90",
|
||||||
|
@ -32,7 +28,6 @@ block:
|
||||||
image.writeFile("tests/images/pathStroke3.png")
|
image.writeFile("tests/images/pathStroke3.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathBlackRectangle"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
let pathStr = "M 10 10 H 90 V 90 H 10 L 10 10"
|
let pathStr = "M 10 10 H 90 V 90 H 10 L 10 10"
|
||||||
let color = rgba(0, 0, 0, 255)
|
let color = rgba(0, 0, 0, 255)
|
||||||
|
@ -40,7 +35,6 @@ block:
|
||||||
image.writeFile("tests/images/pathBlackRectangle.png")
|
image.writeFile("tests/images/pathBlackRectangle.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathYellowRectangle"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
image.fillPath(
|
image.fillPath(
|
||||||
"M 10 10 H 90 V 90 H 10 L 10 10",
|
"M 10 10 H 90 V 90 H 10 L 10 10",
|
||||||
|
@ -49,7 +43,6 @@ block:
|
||||||
image.writeFile("tests/images/pathYellowRectangle.png")
|
image.writeFile("tests/images/pathYellowRectangle.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathRedRectangle"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
var path = newPath()
|
var path = newPath()
|
||||||
path.moveTo(10, 10)
|
path.moveTo(10, 10)
|
||||||
|
@ -64,16 +57,14 @@ block:
|
||||||
image.writeFile("tests/images/pathRedRectangle.png")
|
image.writeFile("tests/images/pathRedRectangle.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathBottomArc"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
image.fillPath(
|
image.fillPath(
|
||||||
"M30 60 A 20 20 0 0 0 90 60 L 30 60",
|
"M30 60 A 20 20 0 0 0 90 60 L 30 60",
|
||||||
parseHtmlColor("#FC427B").rgba
|
parseHtmlColor("#FC427B").rgba
|
||||||
)
|
)
|
||||||
image.writeFile("pathBottomArc.png")
|
image.writeFile("tests/images/pathBottomArc.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathHeart"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
image.fillPath(
|
image.fillPath(
|
||||||
"""
|
"""
|
||||||
|
@ -88,7 +79,6 @@ block:
|
||||||
image.writeFile("tests/images/pathHeart.png")
|
image.writeFile("tests/images/pathHeart.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathRotatedArc"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
image.fillPath(
|
image.fillPath(
|
||||||
"M 20 50 A 20 10 45 1 1 80 50 L 20 50",
|
"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")
|
image.writeFile("tests/images/pathRotatedArc.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathInvertedCornerArc"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
image.fillPath(
|
image.fillPath(
|
||||||
"M 0 50 A 50 50 0 0 0 50 0 L 50 50 L 0 50",
|
"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")
|
image.writeFile("tests/images/pathInvertedCornerArc.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
echo "pathCornerArc"
|
|
||||||
let image = newImage(100, 100)
|
let image = newImage(100, 100)
|
||||||
image.fillPath(
|
image.fillPath(
|
||||||
"M 0 50 A 50 50 0 0 1 50 0 L 50 50 L 0 50",
|
"M 0 50 A 50 50 0 0 1 50 0 L 50 50 L 0 50",
|
||||||
|
|
Loading…
Reference in a new issue