Move vertex-cleanup functions to utils and generalize for non-closed paths
This commit is contained in:
		
							parent
							
								
									79c89b2a4b
								
							
						
					
					
						commit
						8dfb6d4440
					
				@ -6,6 +6,7 @@ from numpy import pi
 | 
				
			|||||||
from . import Shape, normalized_shape_tuple
 | 
					from . import Shape, normalized_shape_tuple
 | 
				
			||||||
from .. import PatternError
 | 
					from .. import PatternError
 | 
				
			||||||
from ..utils import is_scalar, rotation_matrix_2d, vector2
 | 
					from ..utils import is_scalar, rotation_matrix_2d, vector2
 | 
				
			||||||
 | 
					from ..utils import remove_colinear_vertices, remove_duplicate_vertices
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__author__ = 'Jan Petykiewicz'
 | 
					__author__ = 'Jan Petykiewicz'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -267,8 +268,7 @@ class Polygon(Shape):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        :returns: self
 | 
					        :returns: self
 | 
				
			||||||
        '''
 | 
					        '''
 | 
				
			||||||
        duplicates = (self.vertices == numpy.roll(self.vertices, 1, axis=0)).all(axis=1)
 | 
					        self.vertices = remove_duplicate_vertices(self.vertices, closed_path=True)
 | 
				
			||||||
        self.vertices = self.vertices[~duplicates]
 | 
					 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def remove_colinear_vertices(self) -> 'Polygon':
 | 
					    def remove_colinear_vertices(self) -> 'Polygon':
 | 
				
			||||||
@ -277,19 +277,5 @@ class Polygon(Shape):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        :returns: self
 | 
					        :returns: self
 | 
				
			||||||
        '''
 | 
					        '''
 | 
				
			||||||
        dv0 = numpy.roll(self.vertices, 1, axis=0) - self.vertices
 | 
					        self.vertices = remove_colinear_vertices(self.vertices, closed_path=True)
 | 
				
			||||||
        dv1 = numpy.roll(dv0, -1, axis=0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # find cases where at least one coordinate is 0 in successive dv's
 | 
					 | 
				
			||||||
        eq = dv1 == dv0
 | 
					 | 
				
			||||||
        aa_colinear = numpy.logical_and(eq, dv0 == 0).any(axis=1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # find cases where slope is equal
 | 
					 | 
				
			||||||
        with numpy.errstate(divide='ignore', invalid='ignore'):   # don't care about zeroes
 | 
					 | 
				
			||||||
            slope_quotient = (dv0[:, 0] * dv1[:, 1]) / (dv1[:, 0] * dv0[:, 1])
 | 
					 | 
				
			||||||
        slopes_equal = numpy.abs(slope_quotient - 1) < 1e-14
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        colinear = numpy.logical_or(aa_colinear, slopes_equal)
 | 
					 | 
				
			||||||
        self.vertices = self.vertices[~colinear]
 | 
					 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -55,3 +55,35 @@ def rotation_matrix_2d(theta: float) -> numpy.ndarray:
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
    return numpy.array([[numpy.cos(theta), -numpy.sin(theta)],
 | 
					    return numpy.array([[numpy.cos(theta), -numpy.sin(theta)],
 | 
				
			||||||
                        [numpy.sin(theta), +numpy.cos(theta)]])
 | 
					                        [numpy.sin(theta), +numpy.cos(theta)]])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def remove_duplicate_vertices(vertices: numpy.ndarray, closed_path: bool = True) -> numpy.ndarray:
 | 
				
			||||||
 | 
					        duplicates = (vertices == numpy.roll(vertices, 1, axis=0)).all(axis=1)
 | 
				
			||||||
 | 
					        if not closed_path:
 | 
				
			||||||
 | 
					            duplicates[0] = False
 | 
				
			||||||
 | 
					        return vertices[~duplicates]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def remove_colinear_vertices(vertices: numpy.ndarray, closed_path: bool = True) -> numpy.ndarray:
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        Given a list of vertices, remove any superflous vertices (i.e.
 | 
				
			||||||
 | 
					            those which lie along the line formed by their neighbors)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param vertices: Nx2 ndarray of vertices
 | 
				
			||||||
 | 
					        :param closed_path: If True, the vertices are assumed to represent an implicitly
 | 
				
			||||||
 | 
					            closed path. If False, the path is assumed to be open. Default True.
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        # Check for dx0/dy0 == dx1/dy1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dv = numpy.roll(vertices, 1, axis=0) - vertices #[y0 - yn1, y1-y0, ...]
 | 
				
			||||||
 | 
					        dxdy = dv * numpy.roll(dv, 1, axis=0)[:, ::-1] # [[dx1*dy0, dx1*dy0], ...]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dxdy_diff = numpy.abs(numpy.diff(dxdy, axis=1))[:, 0]
 | 
				
			||||||
 | 
					        err_mult = 2 * numpy.abs(dxdy).sum(axis=1) + 1e-40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        slopes_equal = (dxdy_diff / err_mult) < 1e-15
 | 
				
			||||||
 | 
					        if not closed_path:
 | 
				
			||||||
 | 
					            slopes_equal[[0, -1]] = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return vertices[~slopes_equal]
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user