def boundary_envelope(self,node): """ return a polygon that approximates the region that a boundary node can move in without disrupting the boundary too much """ # find it's boundary neighbors: edges = self.edges[self.pnt2edges( node )] boundary_nodes = unique( edges[ edges[:,4]==-1,:2 ] ) if len(boundary_nodes) != 3: print "How can node %i not have some friends on the boundary?"%node print boundary_nodes nodeA,nodeC = setdiff1d(boundary_nodes,[node]) offset = 0.03 # nodes can move 0.1 of the segment length pntA = self.points[nodeA,:2] pntB = self.points[node,:2] pntC = self.points[nodeC,:2] tot_length = norm(pntA-pntB) + norm(pntB-pntC) # first, the rectangle based on AB AB_unit = (pntB-pntA)/norm(pntB-pntA) perp_vec = offset*tot_length*rot(pi/2,AB_unit) pntNW = pntA+perp_vec pntSW = pntA-perp_vec pntNE = pntA + AB_unit*tot_length + perp_vec pntSE = pntA + AB_unit*tot_length - perp_vec AB_ring = array([pntNW,pntSW,pntSE,pntNE]) AB_geom = geometry.Polygon( AB_ring ) # and the rectangle based on BC CB_unit = (pntB-pntC)/norm(pntB-pntC) perp_vec = offset*tot_length*rot(pi/2,CB_unit) pntNW = pntC+perp_vec pntSW = pntC-perp_vec pntNE = pntC + CB_unit*tot_length + perp_vec pntSE = pntC + CB_unit*tot_length - perp_vec CB_ring = array([pntNW,pntSW,pntSE,pntNE]) CB_geom = geometry.Polygon( CB_ring ) return CB_geom.intersection(AB_geom)
def free_node_bounds(points,max_angle=85*pi/180. ): """ assumed that the first point can be moved and the other two are fixed returns an array of vertices that bound the legal region for the free node currently this uses four vertices to approximate the shape of the region """ # try to construct a tight-ish bound on the legal locations for # one node of a triangle where the other two nodes are constrained if len(points) == 3: orig_pntC = points[0] pntA = points[1] # should be oriented such that with A,B,C is CCW pntB = points[2] # make sure the orientation is correct: if dot( rot(pi/2,(pntB-pntA)),orig_pntC - pntA) < 0: pntA,pntB = pntB,pntA else: # we got only the fixed points, which are assumed to be CCW, with # free point to the left of AB pntA,pntB = points # point at the tip of the triangle: pntC1 = 0.5*(pntA+pntB) + rot(pi/2,pntB-pntA)*tan(max_angle)/2 # closest legal point to pntA: pntC2 = pntB + rot(-(pi-2*max_angle), pntA-pntB) # closest legal point to pntB: pntC3 = pntA + rot(pi-2*max_angle, pntB-pntA) # and find the closest point in the middle min_isosc_angle = (pi - max_angle)/2 pntC4 = 0.5*(pntA+pntB) + rot(pi/2,(pntB-pntA))*tan(min_isosc_angle)/2 if 0: C_edges = array([pntC2,pntC1,pntC3,pntC4,pntC2]) plot( C_edges[:,0],C_edges[:,1],'c') return array( [pntC2,pntC1,pntC3,pntC4] )
def rotate_grid(self,angle): """ rotates the oversized grid and translates to get the origin in the right place. """ # translate to get centered on the extra bit we asked for: self.points[:] -= 2*self.dens # rotate self.points[:] = trigrid.rot(angle,self.points) # and get our origin to a nice place self.points[:,0] += self.final_L * np.sin(angle)**2 self.points[:,1] -= self.final_L * np.sin(angle)*np.cos(angle)
def rotate_grid(self, angle): """ rotates the oversized grid and translates to get the origin in the right place. """ # translate to get centered on the extra bit we asked for: self.points[:] -= 2 * self.dens # rotate self.points[:] = trigrid.rot(angle, self.points) # and get our origin to a nice place self.points[:, 0] += self.final_L * np.sin(angle)**2 self.points[:, 1] -= self.final_L * np.sin(angle) * np.cos(angle)
def free_node_bounds_conservative(points,max_angle=85*pi/180.): """ Given the two points, with the intended third point lying to the left, return points describing a polygon the ensures a relatively nice triangle. here nice means that we take the closest point that the new vertex can be, and force the new point to be at least that far away, so avoiding narrow isosceles triangles. """ pntA,pntB = points # point at the tip of the triangle: pntC1 = 0.5*(pntA+pntB) + rot(pi/2,pntB-pntA)*tan(max_angle)/2 l_ab = norm(pntB - pntA) l_leg = l_ab*0.5 / (tan(max_angle/2.) * sin(max_angle) ) pntC2 = pntA + l_leg * (pntC1-pntA) / norm(pntC1-pntA) pntC3 = pntB + l_leg * (pntC1-pntB) / norm(pntC1-pntB) arc_points = [pntC1,pntC2,pntC3] return array( arc_points )
def free_node_bounds_fine(points,max_angle=85*pi/180.,region_steps=3 ): """ assumed that the first point can be moved and the other two are fixed returns an array of vertices that bound the legal region for the free node this version discretizes the curved boundary with variable number of nodes """ # try to construct a tight-ish bound on the legal locations for # one node of a triangle where the other two nodes are constrained if len(points) == 3: orig_pntC = points[0] pntA = points[1] # should be oriented such that with A,B,C is CCW pntB = points[2] # make sure the orientation is correct: if dot( rot(pi/2,(pntB-pntA)),orig_pntC - pntA) < 0: pntA,pntB = pntB,pntA else: # we got only the fixed points, which are assumed to be CCW, with # free point to the left of AB pntA,pntB = points # point at the tip of the triangle: pntC1 = 0.5*(pntA+pntB) + rot(pi/2,pntB-pntA)*tan(max_angle)/2 # # closest legal point to pntA: # pntC2 = pntB + rot(-(pi-2*max_angle), pntA-pntB) # # closest legal point to pntB: # pntC3 = pntA + rot(pi-2*max_angle, pntB-pntA) min_angle_A = pi - 2*max_angle max_angle_A = max_angle arc_points = [pntC1] for angle_A in linspace(min_angle_A,max_angle_A,region_steps): # too lazy to write robust predicate here - just dish it out # to shapely angle_B = pi-max_angle-angle_A # 10 is overkill - I think this can easily be bounded by # the dimensions of the equilateral Aray = pntA + rot(angle_A,10*(pntB-pntA)) Bray = pntB + rot(-angle_B,10*(pntA-pntB)) Aline = geometry.LineString([pntA,Aray]) Bline = geometry.LineString([pntB,Bray]) crossing = Aline.intersection(Bline) try: new_point = array(crossing.coords[0]) except: print "Couldn't find intersection of",crossing print Aline print Bline raise arc_points.append(new_point) arc_points = array(arc_points) return array( arc_points )