Cleanup for version 8.

This commit is contained in:
Juan Pablo Caram 2015-01-02 12:59:06 -05:00
parent 04d028ecc0
commit fe61447887
2 changed files with 203 additions and 203 deletions

View File

@ -14,7 +14,7 @@ from shapely.geometry.base import BaseGeometry
from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos, sign, dot
from numpy.linalg import solve
from mpl_toolkits.axes_grid.anchored_artists import AnchoredDrawingArea
#from mpl_toolkits.axes_grid.anchored_artists import AnchoredDrawingArea
from rtree import index as rtindex

404
camlib.py
View File

@ -17,8 +17,8 @@ import re
import collections
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from scipy.spatial import Delaunay, KDTree
#import matplotlib.pyplot as plt
#from scipy.spatial import Delaunay, KDTree
from rtree import index as rtindex
@ -2982,206 +2982,206 @@ def parse_gerber_number(strnumber, frac_digits):
return int(strnumber)*(10**(-frac_digits))
def voronoi(P):
"""
Returns a list of all edges of the voronoi diagram for the given input points.
"""
delauny = Delaunay(P)
triangles = delauny.points[delauny.vertices]
circum_centers = np.array([triangle_csc(tri) for tri in triangles])
long_lines_endpoints = []
lineIndices = []
for i, triangle in enumerate(triangles):
circum_center = circum_centers[i]
for j, neighbor in enumerate(delauny.neighbors[i]):
if neighbor != -1:
lineIndices.append((i, neighbor))
else:
ps = triangle[(j+1)%3] - triangle[(j-1)%3]
ps = np.array((ps[1], -ps[0]))
middle = (triangle[(j+1)%3] + triangle[(j-1)%3]) * 0.5
di = middle - triangle[j]
ps /= np.linalg.norm(ps)
di /= np.linalg.norm(di)
if np.dot(di, ps) < 0.0:
ps *= -1000.0
else:
ps *= 1000.0
long_lines_endpoints.append(circum_center + ps)
lineIndices.append((i, len(circum_centers) + len(long_lines_endpoints)-1))
vertices = np.vstack((circum_centers, long_lines_endpoints))
# filter out any duplicate lines
lineIndicesSorted = np.sort(lineIndices) # make (1,2) and (2,1) both (1,2)
lineIndicesTupled = [tuple(row) for row in lineIndicesSorted]
lineIndicesUnique = np.unique(lineIndicesTupled)
return vertices, lineIndicesUnique
def triangle_csc(pts):
rows, cols = pts.shape
A = np.bmat([[2 * np.dot(pts, pts.T), np.ones((rows, 1))],
[np.ones((1, rows)), np.zeros((1, 1))]])
b = np.hstack((np.sum(pts * pts, axis=1), np.ones((1))))
x = np.linalg.solve(A,b)
bary_coords = x[:-1]
return np.sum(pts * np.tile(bary_coords.reshape((pts.shape[0], 1)), (1, pts.shape[1])), axis=0)
def voronoi_cell_lines(points, vertices, lineIndices):
"""
Returns a mapping from a voronoi cell to its edges.
:param points: shape (m,2)
:param vertices: shape (n,2)
:param lineIndices: shape (o,2)
:rtype: dict point index -> list of shape (n,2) with vertex indices
"""
kd = KDTree(points)
cells = collections.defaultdict(list)
for i1, i2 in lineIndices:
v1, v2 = vertices[i1], vertices[i2]
mid = (v1+v2)/2
_, (p1Idx, p2Idx) = kd.query(mid, 2)
cells[p1Idx].append((i1, i2))
cells[p2Idx].append((i1, i2))
return cells
def voronoi_edges2polygons(cells):
"""
Transforms cell edges into polygons.
:param cells: as returned from voronoi_cell_lines
:rtype: dict point index -> list of vertex indices which form a polygon
"""
# first, close the outer cells
for pIdx, lineIndices_ in cells.items():
dangling_lines = []
for i1, i2 in lineIndices_:
connections = filter(lambda (i1_, i2_): (i1, i2) != (i1_, i2_) and (i1 == i1_ or i1 == i2_ or i2 == i1_ or i2 == i2_), lineIndices_)
assert 1 <= len(connections) <= 2
if len(connections) == 1:
dangling_lines.append((i1, i2))
assert len(dangling_lines) in [0, 2]
if len(dangling_lines) == 2:
(i11, i12), (i21, i22) = dangling_lines
# determine which line ends are unconnected
connected = filter(lambda (i1,i2): (i1,i2) != (i11,i12) and (i1 == i11 or i2 == i11), lineIndices_)
i11Unconnected = len(connected) == 0
connected = filter(lambda (i1,i2): (i1,i2) != (i21,i22) and (i1 == i21 or i2 == i21), lineIndices_)
i21Unconnected = len(connected) == 0
startIdx = i11 if i11Unconnected else i12
endIdx = i21 if i21Unconnected else i22
cells[pIdx].append((startIdx, endIdx))
# then, form polygons by storing vertex indices in (counter-)clockwise order
polys = dict()
for pIdx, lineIndices_ in cells.items():
# get a directed graph which contains both directions and arbitrarily follow one of both
directedGraph = lineIndices_ + [(i2, i1) for (i1, i2) in lineIndices_]
directedGraphMap = collections.defaultdict(list)
for (i1, i2) in directedGraph:
directedGraphMap[i1].append(i2)
orderedEdges = []
currentEdge = directedGraph[0]
while len(orderedEdges) < len(lineIndices_):
i1 = currentEdge[1]
i2 = directedGraphMap[i1][0] if directedGraphMap[i1][0] != currentEdge[0] else directedGraphMap[i1][1]
nextEdge = (i1, i2)
orderedEdges.append(nextEdge)
currentEdge = nextEdge
polys[pIdx] = [i1 for (i1, i2) in orderedEdges]
return polys
def voronoi_polygons(points):
"""
Returns the voronoi polygon for each input point.
:param points: shape (n,2)
:rtype: list of n polygons where each polygon is an array of vertices
"""
vertices, lineIndices = voronoi(points)
cells = voronoi_cell_lines(points, vertices, lineIndices)
polys = voronoi_edges2polygons(cells)
polylist = []
for i in xrange(len(points)):
poly = vertices[np.asarray(polys[i])]
polylist.append(poly)
return polylist
class Zprofile:
def __init__(self):
# data contains lists of [x, y, z]
self.data = []
# Computed voronoi polygons (shapely)
self.polygons = []
pass
def plot_polygons(self):
axes = plt.subplot(1, 1, 1)
plt.axis([-0.05, 1.05, -0.05, 1.05])
for poly in self.polygons:
p = PolygonPatch(poly, facecolor=np.random.rand(3, 1), alpha=0.3)
axes.add_patch(p)
def init_from_csv(self, filename):
pass
def init_from_string(self, zpstring):
pass
def init_from_list(self, zplist):
self.data = zplist
def generate_polygons(self):
self.polygons = [Polygon(p) for p in voronoi_polygons(array([[x[0], x[1]] for x in self.data]))]
def normalize(self, origin):
pass
def paste(self, path):
"""
Return a list of dictionaries containing the parts of the original
path and their z-axis offset.
"""
# At most one region/polygon will contain the path
containing = [i for i in range(len(self.polygons)) if self.polygons[i].contains(path)]
if len(containing) > 0:
return [{"path": path, "z": self.data[containing[0]][2]}]
# All region indexes that intersect with the path
crossing = [i for i in range(len(self.polygons)) if self.polygons[i].intersects(path)]
return [{"path": path.intersection(self.polygons[i]),
"z": self.data[i][2]} for i in crossing]
# def voronoi(P):
# """
# Returns a list of all edges of the voronoi diagram for the given input points.
# """
# delauny = Delaunay(P)
# triangles = delauny.points[delauny.vertices]
#
# circum_centers = np.array([triangle_csc(tri) for tri in triangles])
# long_lines_endpoints = []
#
# lineIndices = []
# for i, triangle in enumerate(triangles):
# circum_center = circum_centers[i]
# for j, neighbor in enumerate(delauny.neighbors[i]):
# if neighbor != -1:
# lineIndices.append((i, neighbor))
# else:
# ps = triangle[(j+1)%3] - triangle[(j-1)%3]
# ps = np.array((ps[1], -ps[0]))
#
# middle = (triangle[(j+1)%3] + triangle[(j-1)%3]) * 0.5
# di = middle - triangle[j]
#
# ps /= np.linalg.norm(ps)
# di /= np.linalg.norm(di)
#
# if np.dot(di, ps) < 0.0:
# ps *= -1000.0
# else:
# ps *= 1000.0
#
# long_lines_endpoints.append(circum_center + ps)
# lineIndices.append((i, len(circum_centers) + len(long_lines_endpoints)-1))
#
# vertices = np.vstack((circum_centers, long_lines_endpoints))
#
# # filter out any duplicate lines
# lineIndicesSorted = np.sort(lineIndices) # make (1,2) and (2,1) both (1,2)
# lineIndicesTupled = [tuple(row) for row in lineIndicesSorted]
# lineIndicesUnique = np.unique(lineIndicesTupled)
#
# return vertices, lineIndicesUnique
#
#
# def triangle_csc(pts):
# rows, cols = pts.shape
#
# A = np.bmat([[2 * np.dot(pts, pts.T), np.ones((rows, 1))],
# [np.ones((1, rows)), np.zeros((1, 1))]])
#
# b = np.hstack((np.sum(pts * pts, axis=1), np.ones((1))))
# x = np.linalg.solve(A,b)
# bary_coords = x[:-1]
# return np.sum(pts * np.tile(bary_coords.reshape((pts.shape[0], 1)), (1, pts.shape[1])), axis=0)
#
#
# def voronoi_cell_lines(points, vertices, lineIndices):
# """
# Returns a mapping from a voronoi cell to its edges.
#
# :param points: shape (m,2)
# :param vertices: shape (n,2)
# :param lineIndices: shape (o,2)
# :rtype: dict point index -> list of shape (n,2) with vertex indices
# """
# kd = KDTree(points)
#
# cells = collections.defaultdict(list)
# for i1, i2 in lineIndices:
# v1, v2 = vertices[i1], vertices[i2]
# mid = (v1+v2)/2
# _, (p1Idx, p2Idx) = kd.query(mid, 2)
# cells[p1Idx].append((i1, i2))
# cells[p2Idx].append((i1, i2))
#
# return cells
#
#
# def voronoi_edges2polygons(cells):
# """
# Transforms cell edges into polygons.
#
# :param cells: as returned from voronoi_cell_lines
# :rtype: dict point index -> list of vertex indices which form a polygon
# """
#
# # first, close the outer cells
# for pIdx, lineIndices_ in cells.items():
# dangling_lines = []
# for i1, i2 in lineIndices_:
# connections = filter(lambda (i1_, i2_): (i1, i2) != (i1_, i2_) and (i1 == i1_ or i1 == i2_ or i2 == i1_ or i2 == i2_), lineIndices_)
# assert 1 <= len(connections) <= 2
# if len(connections) == 1:
# dangling_lines.append((i1, i2))
# assert len(dangling_lines) in [0, 2]
# if len(dangling_lines) == 2:
# (i11, i12), (i21, i22) = dangling_lines
#
# # determine which line ends are unconnected
# connected = filter(lambda (i1,i2): (i1,i2) != (i11,i12) and (i1 == i11 or i2 == i11), lineIndices_)
# i11Unconnected = len(connected) == 0
#
# connected = filter(lambda (i1,i2): (i1,i2) != (i21,i22) and (i1 == i21 or i2 == i21), lineIndices_)
# i21Unconnected = len(connected) == 0
#
# startIdx = i11 if i11Unconnected else i12
# endIdx = i21 if i21Unconnected else i22
#
# cells[pIdx].append((startIdx, endIdx))
#
# # then, form polygons by storing vertex indices in (counter-)clockwise order
# polys = dict()
# for pIdx, lineIndices_ in cells.items():
# # get a directed graph which contains both directions and arbitrarily follow one of both
# directedGraph = lineIndices_ + [(i2, i1) for (i1, i2) in lineIndices_]
# directedGraphMap = collections.defaultdict(list)
# for (i1, i2) in directedGraph:
# directedGraphMap[i1].append(i2)
# orderedEdges = []
# currentEdge = directedGraph[0]
# while len(orderedEdges) < len(lineIndices_):
# i1 = currentEdge[1]
# i2 = directedGraphMap[i1][0] if directedGraphMap[i1][0] != currentEdge[0] else directedGraphMap[i1][1]
# nextEdge = (i1, i2)
# orderedEdges.append(nextEdge)
# currentEdge = nextEdge
#
# polys[pIdx] = [i1 for (i1, i2) in orderedEdges]
#
# return polys
#
#
# def voronoi_polygons(points):
# """
# Returns the voronoi polygon for each input point.
#
# :param points: shape (n,2)
# :rtype: list of n polygons where each polygon is an array of vertices
# """
# vertices, lineIndices = voronoi(points)
# cells = voronoi_cell_lines(points, vertices, lineIndices)
# polys = voronoi_edges2polygons(cells)
# polylist = []
# for i in xrange(len(points)):
# poly = vertices[np.asarray(polys[i])]
# polylist.append(poly)
# return polylist
#
#
# class Zprofile:
# def __init__(self):
#
# # data contains lists of [x, y, z]
# self.data = []
#
# # Computed voronoi polygons (shapely)
# self.polygons = []
# pass
#
# def plot_polygons(self):
# axes = plt.subplot(1, 1, 1)
#
# plt.axis([-0.05, 1.05, -0.05, 1.05])
#
# for poly in self.polygons:
# p = PolygonPatch(poly, facecolor=np.random.rand(3, 1), alpha=0.3)
# axes.add_patch(p)
#
# def init_from_csv(self, filename):
# pass
#
# def init_from_string(self, zpstring):
# pass
#
# def init_from_list(self, zplist):
# self.data = zplist
#
# def generate_polygons(self):
# self.polygons = [Polygon(p) for p in voronoi_polygons(array([[x[0], x[1]] for x in self.data]))]
#
# def normalize(self, origin):
# pass
#
# def paste(self, path):
# """
# Return a list of dictionaries containing the parts of the original
# path and their z-axis offset.
# """
#
# # At most one region/polygon will contain the path
# containing = [i for i in range(len(self.polygons)) if self.polygons[i].contains(path)]
#
# if len(containing) > 0:
# return [{"path": path, "z": self.data[containing[0]][2]}]
#
# # All region indexes that intersect with the path
# crossing = [i for i in range(len(self.polygons)) if self.polygons[i].intersects(path)]
#
# return [{"path": path.intersection(self.polygons[i]),
# "z": self.data[i][2]} for i in crossing]
def autolist(obj):