convex_hull for faster rotate_and_scale_to_fit
This commit is contained in:
parent
3b35f93223
commit
38c71e1fe5
|
@ -2,7 +2,8 @@ from __future__ import division
|
||||||
|
|
||||||
from math import sin, cos, radians
|
from math import sin, cos, radians
|
||||||
|
|
||||||
from .paths import simplify_paths, sort_paths, join_paths, crop_paths
|
from .paths import (
|
||||||
|
simplify_paths, sort_paths, join_paths, crop_paths, convex_hull)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import cairo
|
import cairo
|
||||||
|
@ -61,10 +62,18 @@ class Drawing(object):
|
||||||
with open(filename, 'w') as fp:
|
with open(filename, 'w') as fp:
|
||||||
fp.write(self.dumps_svg())
|
fp.write(self.dumps_svg())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def points(self):
|
||||||
|
return [(x, y) for path in self.paths for x, y in path]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def convex_hull(self):
|
||||||
|
return convex_hull(self.points)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bounds(self):
|
def bounds(self):
|
||||||
if not self._bounds:
|
if not self._bounds:
|
||||||
points = [(x, y) for path in self.paths for x, y in path]
|
points = self.points
|
||||||
if points:
|
if points:
|
||||||
x1 = min(x for x, y in points)
|
x1 = min(x for x, y in points)
|
||||||
x2 = max(x for x, y in points)
|
x2 = max(x for x, y in points)
|
||||||
|
@ -168,16 +177,18 @@ class Drawing(object):
|
||||||
scale = min(width / self.width, height / self.height)
|
scale = min(width / self.width, height / self.height)
|
||||||
return self.scale(scale, scale).center(width, height)
|
return self.scale(scale, scale).center(width, height)
|
||||||
|
|
||||||
def rotate_and_scale_to_fit(self, width, height, padding=0, step=5):
|
def rotate_and_scale_to_fit(self, width, height, padding=0, step=1):
|
||||||
drawings = []
|
values = []
|
||||||
width -= padding * 2
|
width -= padding * 2
|
||||||
height -= padding * 2
|
height -= padding * 2
|
||||||
|
hull = Drawing([self.convex_hull])
|
||||||
for angle in range(0, 180, step):
|
for angle in range(0, 180, step):
|
||||||
drawing = self.rotate(angle)
|
d = hull.rotate(angle)
|
||||||
scale = min(width / drawing.width, height / drawing.height)
|
scale = min(width / d.width, height / d.height)
|
||||||
drawings.append((scale, angle, drawing))
|
print angle, d.width, d.height
|
||||||
scale, angle, drawing = max(drawings)
|
values.append((scale, angle))
|
||||||
return drawing.scale(scale, scale).center(width, height)
|
scale, angle = max(values)
|
||||||
|
return self.rotate(angle).scale(scale, scale).center(width, height)
|
||||||
|
|
||||||
def remove_paths_outside(self, width, height):
|
def remove_paths_outside(self, width, height):
|
||||||
e = 1e-8
|
e = 1e-8
|
||||||
|
@ -192,11 +203,13 @@ class Drawing(object):
|
||||||
paths.append(path)
|
paths.append(path)
|
||||||
return Drawing(paths)
|
return Drawing(paths)
|
||||||
|
|
||||||
def render(self, scale=109, margin=1, line_width=0.5/25.4, show_bounds=True):
|
def render(self, scale=109, margin=1, line_width=0.5/25.4,
|
||||||
|
use_axi_bounds=True, show_axi_bounds=True):
|
||||||
if cairo is None:
|
if cairo is None:
|
||||||
raise Exception('Drawing.render() requires cairo')
|
raise Exception('Drawing.render() requires cairo')
|
||||||
# x1, y1, x2, y2 = self.bounds
|
x1, y1, x2, y2 = self.bounds
|
||||||
x1, y1, x2, y2 = (0, 0, 12, 8.5)
|
if use_axi_bounds:
|
||||||
|
x1, y1, x2, y2 = (0, 0, 12, 8.5)
|
||||||
w = x2 - x1
|
w = x2 - x1
|
||||||
h = y2 - y1
|
h = y2 - y1
|
||||||
margin *= scale
|
margin *= scale
|
||||||
|
@ -211,7 +224,7 @@ class Drawing(object):
|
||||||
dc.translate(-x1, -y1)
|
dc.translate(-x1, -y1)
|
||||||
dc.set_source_rgb(1, 1, 1)
|
dc.set_source_rgb(1, 1, 1)
|
||||||
dc.paint()
|
dc.paint()
|
||||||
if show_bounds:
|
if show_axi_bounds:
|
||||||
dc.set_source_rgb(0.5, 0.5, 0.5)
|
dc.set_source_rgb(0.5, 0.5, 0.5)
|
||||||
dc.set_line_width(1 / scale)
|
dc.set_line_width(1 / scale)
|
||||||
dc.rectangle(0, 0, 12, 8.5)
|
dc.rectangle(0, 0, 12, 8.5)
|
||||||
|
|
14
axi/paths.py
14
axi/paths.py
|
@ -1,5 +1,5 @@
|
||||||
from math import hypot
|
from math import hypot
|
||||||
from shapely.geometry import LineString
|
from shapely import geometry
|
||||||
|
|
||||||
from .spatial import Index
|
from .spatial import Index
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ def load_paths(filename):
|
||||||
def simplify_path(points, tolerance):
|
def simplify_path(points, tolerance):
|
||||||
if len(points) < 2:
|
if len(points) < 2:
|
||||||
return points
|
return points
|
||||||
line = LineString(points)
|
line = geometry.LineString(points)
|
||||||
line = line.simplify(tolerance, preserve_topology=False)
|
line = line.simplify(tolerance, preserve_topology=False)
|
||||||
return list(line.coords)
|
return list(line.coords)
|
||||||
|
|
||||||
|
@ -109,3 +109,13 @@ def crop_paths(paths, x1, y1, x2, y2):
|
||||||
for path in paths:
|
for path in paths:
|
||||||
result.extend(crop_path(path, x1, y1, x2, y2))
|
result.extend(crop_path(path, x1, y1, x2, y2))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def convex_hull(points):
|
||||||
|
hull = geometry.MultiPoint(points).convex_hull
|
||||||
|
if isinstance(hull, geometry.Polygon):
|
||||||
|
return list(hull.exterior.coords)
|
||||||
|
if isinstance(hull, geometry.LineString):
|
||||||
|
return list(hull.coords)
|
||||||
|
if isinstance(hull, geometry.Point):
|
||||||
|
return list(hull.coords)
|
||||||
|
raise Exception('unhandled convex hull geometry')
|
||||||
|
|
|
@ -84,15 +84,16 @@ def main():
|
||||||
ds = []
|
ds = []
|
||||||
for filename, angle in zip(filenames, angles):
|
for filename, angle in zip(filenames, angles):
|
||||||
ds.append(axi.Drawing(axi.load_paths(filename)).scale_to_fit(8.5, 12).scale(1, -1))
|
ds.append(axi.Drawing(axi.load_paths(filename)).scale_to_fit(8.5, 12).scale(1, -1))
|
||||||
d = grid_drawings(ds, 2, 1)
|
# d = grid_drawings(ds, 2, 1)
|
||||||
|
d = ds[0]
|
||||||
print len(d.paths)
|
print len(d.paths)
|
||||||
print 'joining paths'
|
print 'joining paths'
|
||||||
d = d.join_paths(0.01)
|
d = d.join_paths(0.01)
|
||||||
print len(d.paths)
|
print len(d.paths)
|
||||||
print 'transforming paths'
|
print 'transforming paths'
|
||||||
# d = d.scale(1, -1)
|
# d = d.scale(1, -1)
|
||||||
d = d.rotate_and_scale_to_fit(8.5, 12 - text.height - 0.75, step=5)
|
d = d.rotate_and_scale_to_fit(8.5, 12 - text.height - 0.75)
|
||||||
d = d.origin()
|
# d = d.origin()
|
||||||
print 'sorting paths'
|
print 'sorting paths'
|
||||||
d = d.sort_paths()
|
d = d.sort_paths()
|
||||||
print 'joining paths'
|
print 'joining paths'
|
||||||
|
|
Loading…
Reference in New Issue