def test_scale_polygon_by_one_has_same_vertices(self): vertices = make_square_vertices(side_length=2, center=(2, 2)) polygon = geom.Polygon(vertices) polygon.scale(factor=1) expected = vertices actual = polygon.vertices np.testing.assert_array_equal(expected, actual)
def get_square(self, pos): """ return is a square polygon around position as defined in the paper, with segments starting from right top vertex of the square moving clockwise """ return geom.Polygon([pos + 1/2 * (1+1j), pos + 1/2 * (1-1j), pos + 1/2 * (-1-1j), pos + 1/2 * (-1+1j)])
def convertGeom(self): '''This function converts a Shape class object to the appropriate Geometry.''' import geometry # A module with a bunch of spatial classes if self.geometryType == 'POINT' or self.geometryType == 'MULTIPOINT': pointList = [] for k in self.features.keys(): pt = self.features[k] pointList.append(geometry.Point(pt[0], pt[1])) if len(pointList) > 1: return pointList else: return pointList[0] # Just the single Point elif self.geometryType == 'LINESTRING' or self.geometryType == 'MULTILINESTRING': lineList = self.features.values() # A list of lists of coords ptlnList = [] for line in lineList: ptlist = [] for pt in line: ptlist.append(geometry.Point(pt[0], pt[1])) ptlnList.append(geometry.LineString(ptlist)) if len(ptlnList) > 1: geoInstance = geometry.MultiLineString(ptlnList) return geoInstance else: geoInstance = geometry.LineString(ptlnList[0]) return GeoInstance # Just the single LineString elif self.geometryType == 'POLYGON' or self.geometryType == 'MULTIPOLYGON': geomList = self.features.values() # A list of lists of coords polyList = [] for poly in geomList: ptlnList = [] for ring in poly: ptlist = [] for pt in ring: ptlist.append(geometry.Point(pt[0], pt[1])) ptlnList.append(geometry.LineString(ptlist)) if len(ptlnList) > 1: # If there are holes polyList.append(geometry.Polygon(ptlnList[0], ptlnList[1:])) else: polyList.append(geometry.Polygon(ptlnList[0])) if len(polyList) > 1: # it's a multiPolygon geoInstance = geometry.MultiPolygon(polyList) return geoInstance else: return polyList[0] # Just the polygon
def test_scale_polygon_by_ten(self): polygon = geom.Polygon( make_square_vertices(side_length=2, center=(2, 2))) polygon.scale(factor=10) expected = make_square_vertices(side_length=20, center=(2, 2)) actual = polygon.vertices np.testing.assert_array_equal(expected, actual)
def test_point_in_nonconvex_polygon_throws(self): # Arrange vertices = make_square_vertices(side_length=2, center=(0, 0)) + [[0, 0]] nonconvex = geom.Polygon(vertices) # Assert self.assertRaises(ValueError, nonconvex.point_in_convex_polygon, (0, 0))
def get_square(self, pos): """ return is the square polygon which contains pos as defined in the paper, with segments starting from right top vertex of the square moving clockwise """ pos = round(pos.real, 0) + round(pos.imag, 0) * 1j return geom.Polygon([pos + 1/2 * (1+1j), pos + 1/2 * (1-1j), pos + 1/2 * (-1-1j), pos + 1/2 * (-1+1j)])
def test_point_on_polygon_corner(self): # Arrange square = geom.Polygon( make_square_vertices(side_length=2, center=(0, 0))) # Act expected = True actual = square.point_in_convex_polygon((1, 1)) # Assert self.assertEqual(expected, actual)
def __init__(self, key, contour): self.id = key self.contour = contour self.polygon = geo.Polygon(contour) self.polygon.get_circumcircle() self.circumcircle = self.polygon.circumcircle self.circumcenter = self.circumcircle.c self.circumdiameter = self.polygon.circumdiameter self.area = self.polygon.area self.cables = [] self.ncables = 0 self.naxons = 0
def build_contours(self): """ Build the contours of the nerve Contour processing We obtain five contour variables: 1. contour: The actual contours dictionary we are going to use. Its number of points may be lower than it contains in the file. 2. contour_hd: The contours with all their points, no reduction. 3. contour_pslg: The contours in PSLG format 4. contour_nerve: Contour for the nerve only, in order to triangulate it and fill it with points. 5. contour_pslg_nerve: Contour for the nerve only in PSLG format. """ c_reduction = self.c_reduction # Open contour contour = cth.load_contours(self.cpath) # Save the original contours, I will need them to prevent axons from protruding # out of the fascicles contour_hd = copy.deepcopy(contour) # Take just one fraction of the points in case they are too many contour = cth.reduce_points(contour, c_reduction) # Convert to PSLG contour_pslg = cth.c2pslg(contour) # Ony the nerve contour_nerve = {'Nerve': contour['Nerve']} contour_pslg_nerve = cth.c2pslg(contour_nerve) # Save all the types of contours self.contour = contour self.contour_nerve = contour_nerve self.contour_hd = contour_hd self.contour_pslg = contour_pslg self.contour_pslg_nerve = contour_pslg_nerve # Save other properties self.polygon = geo.Polygon(np.array(contour_nerve['Nerve'])) # self.centroid = self.polygon.centroid self.crss_area = self.polygon.area # self.polygon.get_circumcircle() self.circumcircle = self.polygon.circumcircle self.circumcenter = self.circumcircle.c self.circumradius = self.circumcircle.r self.circumdiameter = self.polygon.circumdiameter # Instantiate fascicles self.build_fascicles()
def mouseClick(button, state, x, y): global helpActive global polygons global nails global isDrawingPolygon global windowHeight global mouseX global mouseY global grabbedPoint global grabbedPolygon # The user can only draw while the help menu isn't shown. if not helpActive: if (button == GLUT_LEFT_BUTTON and state == GLUT_DOWN): if not isDrawingPolygon: # Grabs the polygon clicked by the mouse that is closest to the viewer. for polygon in reversed(polygons): if geometry.Polygon(polygon.vertexes).contains( geometry.Point(x, windowHeight - y)): grabbedPolygon = polygon grabbedPoint = Vertex(x, windowHeight - y) return # If no polygon was clicked, begins drawing a new polygon. polygons.append(Polygon(x, windowHeight - y)) isDrawingPolygon = True # If the user is currently drawing a polygon and clicks once more. else: # Tests whether the current polygon can be finished, and if it can, it becomes a complete polygon and the drawing ends. if polygons[-1].vertexes[0] == Vertex( x, windowHeight - y) and len(polygons[-1].vertexes) > 2: if polygons[-1].canFinishPolygon(): isDrawingPolygon = False polygons[-1].triangulate() # If not, the position the user clicked becomes a new vertex of the polygon, as long as it does not intersect with one of its sides. else: polygons[-1].addVertex(x, windowHeight - y) # When the mouse button is raised, the polygon isn't moved anymore. if (button == GLUT_LEFT_BUTTON and state == GLUT_UP): if grabbedPolygon != None: grabbedPoint = None grabbedPolygon = None rotationPoint = None if (button == GLUT_RIGHT_BUTTON and state == GLUT_DOWN): if not isDrawingPolygon: # Remove a nail in the location for nail in nails: if Vertex(nail.x, nail.y) == Vertex(x, windowHeight - y): nail.father.children.remove(nail.child) nail.child.father = None nail.child.fatherNail = None nails.remove(nail) return # Add a nail to a pair of polygons for i in reversed(range(0, len(polygons))): if geometry.Polygon(polygons[i].vertexes).contains( geometry.Point(x, windowHeight - y)): for j in reversed(range(0, i)): if geometry.Polygon(polygons[j].vertexes).contains( geometry.Point(x, windowHeight - y)): if polygons[i].father == None: polygons[i].father = polygons[j] polygons[i].fatherNail = Nail( x, windowHeight - y, polygons[j], polygons[i]) polygons[j].children.append(polygons[i]) nails.append(polygons[i].fatherNail) return # Cancel drawing a polygon. else: isDrawingPolygon = False polygons.pop() glutPostRedisplay()
import geometry pt1 = geometry.Point(1, 1) pt2 = geometry.Point(1, 3) pt3 = geometry.Point(2, 5) pt4 = geometry.Point(3, 2) pt5 = geometry.Point(3, 4) pt6 = geometry.Point(5, 4) pt7 = geometry.Point(7, 1) pt8 = geometry.Point(2, 2) pt9 = geometry.Point(3, 3) pt10 = geometry.Point(4, 2) # Lines line1 = geometry.LineString([pt1, pt2, pt5, pt7, pt1]) line2 = geometry.LineString([pt8, pt9, pt10, pt8]) line1.draw('red', mapwin, 1) mapwin.display() # Polygons poly1 = geometry.Polygon(line1) poly1.envelope poly1.Area() poly1.draw('blue', mapwin) mapwin.display() poly2 = geometry.Polygon(line1, [line2]) poly2.draw('red', mapwin) mapwin.display()
def crop_diagram(gc, pairs, segments, pvpts, lines, contour): """ Crop the diagram using a contour """ segments = get_far_points(gc, segments, pvpts, lines) # Calculate limits cont_xy = contour['vertices'] # cont_sg = cont_xy[contour['segments']] contour_polygon = geo.Polygon(cont_xy) x, y = np.array(cont_xy).T xmin, xmax = x.min(), x.max() ymin, ymax = y.min(), y.max() dx = xmax - xmin dy = ymax - ymin # Now get the intersection between a pair's segment and the contour for pair in pairs: seg = segments[pair] if isinstance(seg, geo.Segment): # First off, if the segment is completely outside the contour, # remove it a, b = seg.a, seg.b discard = (not contour_polygon.contains_point(a)) and ( not contour_polygon.contains_point(b)) if not discard: for cs in contour_polygon.segments.values(): # xyint = geo.intersection_segments(seg, geo.Segment(cs)) xyint = geo.intersection_segments(seg, cs) if xyint != (np.nan, np.nan): # We found an intersection between the segment and the # contour # Now the point to be replaced is the one falling outside if contour_polygon.contains_point(a): change = 1 elif contour_polygon.contains_point(b): change = 0 # the contour seg.change_point(change, xyint) # We're done with this loop break # Sanity Check after cutting it # If any segment is even partially outside the contour, remove it # I've seen this happen when a segment has one point # outside and one right on the contour, for which no # intersection is found and hence it's left as is # Check if any point is detected to be outside the contour (being # on it may yield True, unfortunately), so in that case, check = (not contour_polygon.contains_point(a)) or ( not contour_polygon.contains_point(b)) if check: # roughly check if it's really outside. In that # case, it may be really really far (thus be a # long segment) discard = seg.length > 10. * np.hypot(dx, dy) if discard: ws.log('Discarding %s' % str(pair)) ws.log(str(contour_polygon.contains_point(seg.a))) ws.log(str(seg.points.flatten())) ws.log(str(seg)) ws.log('length = %s, dx = %s, dy = %s' % (str(seg.length), str(dx), str(dy))) ws.log("") segments[pair] = [None] else: # Add the segment segments[pair] = seg else: # Add the segment segments[pair] = seg else: # This is not good doing anymore # segments[pair] = [None] pass # List pairs again pairs = list(segments.keys()) return segments
def get_polygons(self): """ Create the polygons for each cell """ segments = self.segments x, y = self.x, self.y nc = self.nc cellverts = OrderedDict() polygons = OrderedDict() polg_areas = np.zeros(nc) # Add vertices to the cells for (i, j), seg in segments.items(): try: a, b = seg.a, seg.b except AttributeError: # This means that some segment was [None] print("None segment for (%i, %i)" % (i, j)) pass else: cellverts = tools.append_items(cellverts, i, [a, b]) cellverts = tools.append_items(cellverts, j, [a, b]) # Set vertices for i in range(nc): points = np.array(cellverts[i]) # Reshape if points.shape[-1] == 1: points = points.reshape(points.shape[:-1]) # Set them points = np.unique(points, axis=0) # Sort points by angle cellpoint = (x[i], y[i]) # Sort them by angle. Use some averaged centroid rather than # the cellpoint itself. Because if cellpoint is included, it # may be confusing and the sorting can go wrong # This is OK, since the polygon is always convex points = geo.sort_by_angle(points) cellverts[i] = points # Create polygon pol = geo.Polygon(points) # Check that the polygon contains the point or this is on # the contour, at least. If not, add it to the polygon polccell = pol.contains_point(cellpoint) # if False: if not polccell: points = np.append(points.tolist(), [list(cellpoint)], axis=0) points = geo.sort_by_angle(points) cellverts[i] = points pol = geo.Polygon(points) try: polg_areas[i] = pol.area except AttributeError: # This is not a polygon pass else: # If it is, save it polygons[i] = pol # Store in attributes self.cellverts = cellverts self.polygons = polygons self.polg_areas = polg_areas self.free_areas = polg_areas - self.circ_areas
def mill_lenses(outdir, order): def to_polar(polyline): return [[-math.sqrt(p[0]**2 + p[1]**2), math.degrees(math.atan2(p[1],p[0])) + 180] for p in polyline] """ Creates g-code for milling the left and right lenses for the frames.""" lens = g.Polygon(order['lhole_con']) x = lens.bounding_box() box = lens.bounding_box() center = g.Point((box.p2.x+box.p1.x)/2, (box.p2.y+box.p1.y)/2) shift_to_origin = g.Vector(-center.x, -center.y) lens = g.translate_polygon(lens, shift_to_origin) polar = g.polygon_to_uniform_polar(lens, 1500) # Inflate the polar form by 1/2 the diameter of the cutter, and convert # the angles to degrees tau = math.pi * 2 conv = 360/tau roughing = [(pt.theta*conv, pt.r+4.77) for pt in polar] # Expand for the roughing cut # left_lens_rough = poly.dilate(4.77, left_lens) # Convert to polar coordinates # left_lens_roughing_polar = to_polar(left_lens_rough) # Start the cut from 0 degrees # angle_list = [p[1] for p in left_lens_roughing_polar] # zero_idx = angle_list.index(min(angle_list)) # left_lens_roughing_polar = left_lens_roughing_polar[zero_idx:] + left_lens_roughing_polar[:zero_idx] # Cut it down to every 0.2 degrees # coarse = [] # for idx, pt in enumerate(left_lens_roughing_polar): # if idx == 0 or (pt[1]-coarse[-1][1]) >= 0.2: # coarse.append(pt) # The polar distances aren't correct quite. That's because the conversion assumed a flat # surface, but we'll actually be bending that contour around a sphere. The lens is already # spherical. So we need to adjust inwards a bit to account for the x distance actually being an arc # distance. # The radius of the sphere is 88mm (base 6 lens). ArcLength = Radius * angle, and chord # length is sin(angle) * radius. roughing = [(p[0], math.sin(-p[1]/88) * 88) for p in roughing] roughing.sort(key=lambda pt: pt[0]) closest = max([p[1] for p in roughing]) if abs(closest) < 22.5: print "Error! Cannot cut lens, it's too small.", closest roughing_reversed = [[-1*(math.degrees(-math.radians(p[1]))+360), p[1]] for p in roughing] program = [ cam.setup(), cam.select_fixture("lens_clamp"), cam.retract_spindle(), cam.change_tool("1/4in endmill"), cam.start_spindle(20000), cam.rapid([-50, 0]), ["G1 Z0 F500"], cam.polar_contour(roughing), ["G1 X-50"], ["G1 A0"], cam.stop_spindle(), cam.retract_spindle(), cam.end_program(), ] open(outdir + "/left_lens.ngc", "w").write(to_string(program)) program = [ cam.setup(), cam.select_fixture("lens_clamp"), cam.retract_spindle(), cam.change_tool("1/4in endmill"), cam.start_spindle(20000), cam.rapid([-50, 0]), ["G1 Z0 F500"], cam.polar_contour(roughing_reversed), ["G1 X-50"], ["G1 A0"], cam.stop_spindle(), cam.retract_spindle(), cam.end_program(), ] open(outdir + "/right_lens.ngc", "w").write(to_string(program))
def process_results(path, ec_key, dataset_name): """ Read and process the results from this dataset""" print(path, dataset_name, ec_key) # Results folder results_folder = os.path.join(path, 'data/results') # List all the items in the results folder items = sorted(os.listdir(results_folder)) # Select the csv files items = [item for item in items if ".csv" in item] # Select the axon recording files items = [item for item in items if item[:4] == "Axon"] # Array for the axons' activity maxima maxima = [] # AP peak times appt_ = {} # AP latency times aplt_ = {} # Flags indicating which axons did fire and which not hasAP = {} # Voltage data data = {} # Geometrical properties xx_ = [] yy_ = [] rr_ = [] # Iterate over the files and read them for filename in items: # Actually, i is taken from the file name i = int(filename.replace('Axon', '').replace('.csv', '')) data[i] = {} with open(os.path.join(results_folder, filename), "r") as f: fr = csv.reader(f) for row in fr: r0 = row[0] if ("NODE" in r0) or ("node" in r0): data[i][key].append([float(x) for x in row[1:]]) elif len(row) == 3: xx_.append(float(r0)) yy_.append(float(row[1])) rr_.append(float(row[2])) elif len(row) == 1: try: # print(key) data[i][key] = np.array(data[i][key]) except NameError: # There's no key yet pass key = r0 data[i][key] = [] # When the last key is read, don't forget storing it data[i][key] = np.array(data[i][key]) del key # Check maxima and relevant stuff vcrit = 15. for i, data_ in data.items(): axondata = data_["v"] # Check if the maximum is an AP # print(axondata) maximum = axondata.max() maxima.append(maximum) if maximum > 0: # Regions where v is greater than vcrit whereAPs = np.where(axondata > vcrit) # Time when the first AP is fired (v rises above vcrit mV) when1stAP = whereAPs[1].min() where1stAP = whereAPs[0][np.where(whereAPs[1] == when1stAP)][0] segment_maxima = argrelextrema(axondata[where1stAP], np.greater)[0] # Local maxima local_maxima = axondata[where1stAP][segment_maxima] # Local maxima greater than vcrit mV # IMPORTANT: I named the following variable when1stAP_ just so # it doesn't overwrite when1stAP, but I can make it overwrite # it if I want when1stAP_ = segment_maxima[np.where(local_maxima > vcrit)][0] if True: APpeaktime = dt * (when1stAP - 1) appt_[i] = APpeaktime aplt_[i] = APpeaktime - 0.01 hasAP[i] = True else: hasAP[i] = False aplt_[i] = 'nan' i += 1 # Maxima to array maxima = np.array(maxima) # AP peak times to array # And subtract the pulse delay from them appt_values = np.array(list(appt_.values())) - 0.01 if len(appt_values) == 0: # print("No axon fired an AP") pass # sys.exit() # Geometrical properties to array xx_ = np.array(xx_) yy_ = np.array(yy_) rr_ = np.array(rr_) # Topology # Open and read topology file topo_path = os.path.join(path, 'data/load/created_nerve_internal_topology.json') with open(topo_path, 'r') as f: topology = json.load(f) # Open and read the contours file contours_file = os.path.join(path, 'data/load/created_nerve_contour.csv') contours = {} with open(contours_file, "r") as f: fr = csv.reader(f) for row in fr: try: # Try to get numbers x = float(row[0]) except ValueError: # It's a string key = row[0] contours[key] = [] else: y = float(row[1]) # Append the point to the corresponding contour contours[key].append([x, y]) # Delete the key for tidyness del key # Polygons for each fascicle and the nerve polygons = {} for k, c in contours.items(): pol = geo.Polygon(c) polygons[k] = pol.plpol # Fired axons per fascicle and in total in the nerve fascicle_ap_counter = {} for k in contours: if 'ascicle' in k: fascicle_ap_counter[k] = 0 # Find them for i, b in hasAP.items(): if b: # Find fascicle of this axon for k, p in polygons.items(): if 'ascicle' in k: if p.contains_point((xx_[i], yy_[i])): # print('Axon %i is in %s'%(i, k)) fascicle_ap_counter[k] += 1 break # Read electrode settings settings_path = os.path.join(path, 'settings/electrodes.json') with open(settings_path, 'r') as f: stim_settings = json.load(f) current = list(list(stim_settings.values())[0]['stimulation protocol'].values())[0]['currents'][0] total_number_APs = sum(list(fascicle_ap_counter.values())) # Dictionary to gather all the important data data_final = OrderedDict() data_final['dataset_name'] = dataset_name data_final['current'] = current data_final['fascicle_ap_counter'] = fascicle_ap_counter data_final['total_number_APs'] = total_number_APs data_final['AP times'] = aplt_ # Save the data in the 'all data' dictionary data_all[dataset_name] = data_final # Save data into the data_recruitment dictionary data_recruitment['currents'].append(current) data_recruitment['recruitment'][ec_key]['nerve'].append(total_number_APs) for k, n in fascicle_ap_counter.items(): data_recruitment['recruitment'][ec_key][k].append(n) # Save results in a json file with open('stim_results_%s%s'%(dataset_name, '.json'), 'w') as f: json.dump(data_final, f, indent=4)
import unittest # build the board in the example at # https://github.com/CBCJVM/CBCJVM/wiki/pathfinding_proposal # This is kind of an s-curve # (0, 0) ______________ ________ (5, 0) # | (3, 0)| E |(4, 0) | # | | | | # | (1, 1) ______| | | # | | (3, 1) | | # | | ______|(4, 2) | # | | |(2, 2) | # | | | | # |_(1,_3)| S |(2,_3)___(5,_3)| # (0, 3) s_left_side = geometry.Polygon((0, 0), (3, 0), (3, 1), (1, 1), (1, 3), (0, 3), ccw=False) s_right_side = geometry.Polygon((4, 0), (5, 0), (5, 3), (2, 3), (2, 2), (4, 2), ccw=False) s_board = mapping.Board() s_board.add(s_left_side) s_board.add(s_right_side) s_start = Node(1.5, 3) s_end = Node(3.5, 0) # del left_side; del right_side # A simple rectangular board, to test that a path cannot pass through a polygon # (0, 0) ________ (1, 0) # | | # | | # |________| # (0, 1) (1, 1)
def _polygon_to_kml(polygon, kmlcolor="ff0000ff", outline=0): ###problematic """return the KML equivalent for a geometry.Polygon""" coords = [v[:2] + (0, ) for v in polygon.vertices] # lat./long. only kml_coords = '\n' + '\n'.join( [','.join([str(e) for e in c]) + '.' + '\n' for c in coords]) return ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + lxml.etree.tostring(KML.kml( KML.PlaceMark( KML.Polygon( KML.extrude(1), KML.altitudeMode("relativeToGround"), KML.outerBoundaryIs( KML.LinearRing(KML.coordinates(kml_coords)))))), pretty_print=True)) def triangulate(*circles): #####contingent upon geometry.Circle.intersect """triangulate a polygon based on a set of circles""" pass def triangulate_to_kml(*circles): """return a KML document based on triangulation results""" return _polygon_to_kml(triangulate(*circles)) if __name__ == "__main__": kml = _polygon_to_kml(geometry.Polygon((-1, -1), (-1, 1), (1, 1), (1, -1))) print kml print >> open("triangulate-test.kml", "w"), kml print "Written to triangulate-test.kml"