"""Line drawings (SVG and the fan-art designs) joined into one sand-table path.
Run from the software folder: python3 -m unittest discover -s tests -v"""
import math
import os
import sys
import tempfile
import unittest
os.environ['SANDTABLE_QUIET'] = '1'
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'tools'))
from sandtable import config, thr
from sandtable.lineart import drawing_to_polar, join_strokes, path_polylines, svg_strokes
SVG = """"""
def unit_xy(pts):
return [(r * math.cos(t), r * math.sin(t)) for t, r in pts]
class TestSvg(unittest.TestCase):
def test_shapes_and_transforms(self):
s = svg_strokes(SVG)
self.assertEqual(len(s), 3) # defs and text are skipped
circle = s[1]
self.assertAlmostEqual(max(p[0] for p in circle), 70, delta=0.1) # r 10 scaled 2x, moved to 50
self.assertAlmostEqual(min(p[0] for p in circle), 30, delta=0.1)
path = s[2]
self.assertAlmostEqual(math.dist(path[0], path[-1]), 0, places=6) # z closes it
self.assertAlmostEqual(min(p[1] for p in path), 70, delta=0.6) # the arc's top (centre 70,80, r 10)
def test_arc_and_relative(self):
(semi,) = path_polylines('M0 0 a10 10 0 0 1 20 0', tol=0.1)
self.assertAlmostEqual(min(p[1] for p in semi), -10, delta=0.05) # sweep 1 bulges up the page (y down)
lines = path_polylines('m0 0 l10 0 10 0 M0 5 H20 V9')
self.assertEqual(lines[0][-1], (20.0, 0.0)) # implicit repeated l
self.assertEqual(lines[1][-1], (20.0, 9.0))
class TestJoin(unittest.TestCase):
def check_path(self, xy, strokes):
for a, b in zip(xy, xy[1:]):
self.assertLess(math.dist(a, b), 0.008) # one continuous line
for end in (xy[0], xy[-1]):
r = math.hypot(*end)
self.assertTrue(r < 1e-9 or abs(r - 1) < 1e-9, end) # starts and ends at the centre or the edge
for st in strokes: # every stroke is drawn
for p in st[::7]:
self.assertLess(min(math.dist(p, q) for q in xy), 0.01)
def test_triangle_from_three_lines_needs_no_jumps(self):
a, b, c = (0.0, 0.85), (-0.74, -0.42), (0.74, -0.42)
strokes = [[a, b], [c, b], [c, a]]
stats = {}
xy = join_strokes(strokes, stats=stats)
self.check_path(xy, strokes)
self.assertLess(stats['jump'], 0.35) # only the short lines in from and out to the edge
def test_separate_shapes(self):
sq = lambda x, y, d: [(x, y), (x + d, y), (x + d, y + d), (x, y + d), (x, y)]
strokes = [sq(-0.6, -0.6, 0.3), sq(0.3, 0.3, 0.3), sq(0.3, -0.6, 0.3), [(-0.5, 0.5), (-0.2, 0.2)]]
xy = join_strokes(strokes)
self.check_path(xy, strokes)
def test_fan_art_designs(self):
try:
import make_fan_art # not in the public repository (trademarks)
except ImportError:
self.skipTest('tools/make_fan_art.py is not here')
for name, (fn, opts) in make_fan_art.DESIGNS.items():
pts = drawing_to_polar(fn(), **opts)
self.assertGreater(len(pts), 100, name)
for end in (pts[0][1], pts[-1][1]):
self.assertTrue(end < 0.02 or end > 0.98, f'{name} ends at rho {end}')
xy = unit_xy(pts)
for a, b in zip(xy, xy[1:]):
self.assertLess(math.dist(a, b), 0.06, name)
class TestUpload(unittest.TestCase):
def test_svg_upload_becomes_a_design(self):
from sandtable.web import Library
with tempfile.TemporaryDirectory() as d:
lib = Library(config.load('/nonexistent.toml'), root=os.path.join(d, 'p'), cache=os.path.join(d, 'c'),
removed=os.path.join(d, 'r'))
ident = lib.add('My Logo.svg', SVG)
self.assertEqual(ident, 'uploads/My-Logo.thr')
pts = thr.load(lib.path(ident))
self.assertGreater(len(pts), 100)
with self.assertRaises(ValueError):
lib.add('empty.svg', '')
if __name__ == '__main__':
unittest.main()