def __init__(self, args): ''' LineModified class ''' if isinstance(args[1], sym.Point): self.obj = sym.Line(*args) else: self.obj = sym.Line(args[0], slope=args[1])
def get_l_focal(hue=45): """ hueから L_focal を得る """ # まずは L_cusp を求める # --------------------- lab_709, lab_2020, rgb = get_lab_edge(hue) chroma_709 = get_chroma(lab_709) chroma_2020 = get_chroma(lab_2020) bt709_cusp_idx = np.argmax(chroma_709) bt2020_cusp_idx = np.argmax(chroma_2020) bt709_point = sympy.Point(chroma_709[bt709_cusp_idx], lab_709[bt709_cusp_idx, 0]) bt2020_point = sympy.Point(chroma_2020[bt2020_cusp_idx], lab_2020[bt2020_cusp_idx, 0]) chroma_line = sympy.Line(bt709_point, bt2020_point) lightness_line = sympy.Line(sympy.Point(0, 0), sympy.Point(0, 100)) intersection = sympy.intersection(chroma_line, lightness_line)[0].evalf() l_cusp = np.array(intersection) # BT.2407 に従って補正 # --------------------- # plot ax1 = pu.plot_1_graph(fontsize=20, figsize=(10, 8), graph_title=None, graph_title_size=None, xlabel="Chroma", ylabel="Lightness", axis_label_size=None, legend_size=17, xlim=[0, 220], ylim=[0, 100], xtick=None, ytick=None, xtick_size=None, ytick_size=None, linewidth=3) ax1.plot(chroma_709, lab_709[..., 0], c="#808080", label='BT.709') ax1.plot(chroma_2020, lab_2020[..., 0], c="#000000", label='BT.2020') ax1.plot(chroma_709[bt709_cusp_idx], lab_709[bt709_cusp_idx, 0], 'or', markersize=10, alpha=0.5) ax1.plot(chroma_2020[bt2020_cusp_idx], lab_2020[bt2020_cusp_idx, 0], 'or', markersize=10, alpha=0.5) ax1.plot(l_cusp[0], l_cusp[1], 'ok', markersize=10, alpha=0.5) # annotation ax1.annotate(r'L^*_{cusp}', xy=(l_cusp[0], l_cusp[1]), xytext=(l_cusp[0] + 10, l_cusp[1] + 10), arrowprops=dict(facecolor='black', shrink=0.1)) ax1.plot([chroma_2020[bt2020_cusp_idx], l_cusp[0]], [lab_2020[bt2020_cusp_idx, 0], l_cusp[1]], '--k', alpha=0.3) plt.legend(loc='upper right') plt.show()
def intersection_of_plane_with_slice(slice_index, plane): """ ASSUMING AXIAL ORIENTATION, finds the line that repreents the interection between the two planes IN 2D Parameters ---------- slice_index : int the z index of the axial slice. plane : sympy Plane object The plane of interest. Returns ------- sympy Line2D object. """ # set up the plane of the slice flat_plane = sp.Plane((1, 0, slice_index), (-1, 0, slice_index), (0, 1, slice_index)) inter = plane.intersection(flat_plane)[0] intersection_2d = sp.Line((inter.p1[0], inter.p1[1]), (inter.p2[0], inter.p2[1])) return intersection_2d
def calculate_projected_plane_coords(slice_index, plane, x_domain=(0, 500)): """ Gets the coordinates the interection of a plane with your axial slice, primarily for plotting purposes Parameters ---------- slice_index : int index of the axial slice plane : sympy Plane object Plane to be drawn. x_domain: tuple of ints or floats The domain to be plotted on Returns ------- Tuple of lists containing the x and y coords of the intersecting line. """ inter = intersection_of_plane_with_slice(slice_index, plane) intersection_2d = sp.Line((inter.p1[0], inter.p1[1]), (inter.p2[0], inter.p2[1])) exes = np.arange(x_domain[0], x_domain[1]) whys = [evaluate_x_on_line(x, intersection_2d) for x in exes] return exes, whys
def revisit_geometry(json_data): """ https://cis2020-revisit-geometry.herokuapp.com/instructions Wrapper around revisit_geometry :param json_data: raw json data :rtype: dict """ # parse data shape_coord = json_data["shapeCoordinates"] shape_coord = [(d["x"], d["y"]) for d in shape_coord] line_coord = json_data["lineCoordinates"] line_coord = [(d["x"], d["y"]) for d in line_coord] # sympy logic polygon = sympy.Polygon(*shape_coord) line = sympy.Line(*line_coord) intersections = polygon.intersection(line) json_results = [{ "x": round(float(pt.x), 2), "y": round(float(pt.y), 2) } for pt in intersections] return json_results
def fill(xPoly, yPoly, alpha, d): polyArray = [] x, y = rotate(xPoly, yPoly, alpha) for i in range(len(x)): polyArray.append((x[i], y[i])) poly = sympy.Polygon(*polyArray) reverse = False real = 0 printed = 0 minX = min(x) minY = min(y) maxX = max(x) maxY = max(y) count = (maxY - minY) / d inter = [] xFilled = [] yFilled = [] while printed < count: real += d l = sympy.Line((minX, minY + real), (maxY, minY + real)) inter.append(poly.intersection(l)) for i in range(len(inter[printed]) - 1): tempL = sympy.Segment(inter[printed][i], inter[printed][i + 1]) if poly.encloses_point(tempL.midpoint): if reverse: inter[printed] = np.flip(inter[printed], axis=0) xFilled.append(inter[printed][i][0]) xFilled.append(inter[printed][i + 1][0]) yFilled.append(inter[printed][i][1]) yFilled.append(inter[printed][i + 1][1]) reverse = not reverse print(printed) printed += 1 xFinal, yFinal = rotate(xFilled, yFilled, -1 * alpha) return xFinal, yFinal
def hough_to_sympy(x): r, theta = x[0][0], x[0][1] a = np.cos(theta) b = np.sin(theta) x0, y0 = a * r, b * r return sp.Line(sp.Point(x0 + 2000. * b, y0 - 2000. * a), sp.Point(x0 - 2000. * b, y0 + 2000. * a))
def eigenlayers_fix(eign: np.ndarray, vectors: np.ndarray, scape: bool = False) -> np.ndarray: """Orients the plane calculate from the pieces. """ eign = eign.copy() eign2 = sy.Line(eign[2][0], eign[2][-1]) angles_layer = [] for sse in vectors: angles_layer.append( math.degrees(sy.Line(sse[0], sse[-1]).angle_between(eign2))) # Fix layer direction if len(vectors) > 3: do_flip = np.isclose(angles_layer, [ 180, ] * len(angles_layer), atol=40) do_flip = sum(do_flip) >= len(do_flip) - 1 else: do_flip = np.allclose(angles_layer, [ 180, ] * len(angles_layer), atol=40) # Fix vectors -> switch side and layer if len(vectors) > 3: do_switch = [ not x for x in np.isclose(angles_layer, [ 0, ] * len(angles_layer), atol=40) ] do_switch = sum(do_switch) >= len(do_switch) - 1 else: do_switch = not np.allclose(angles_layer, [ 0, ] * len(angles_layer), atol=35) # Apply if do_flip: eign[2] = [list(x) for x in np.flip(np.asarray(eign[2]), axis=0)] elif do_switch and not scape: eign[[1, 2]] = eign[[2, 1]] eign = eigenlayers_fix(eign, vectors, True) return eign
def set_border(self, lst): ''' in order to draw lines or rays, this class needs the border of the plot if the trait list is loaded before the image, this information is missing hence, in such a case, the list of traits to be visualized are passed to this method the "bLines" will be overwrittern if an image is loaded to gui and passed to this class this method is called only if the traits are visualized and an image is not available ''' X, Y = [], [] for trait in lst: if isinstance(trait, trts.SegmentModified): X.append(trait.obj.p1.x) X.append(trait.obj.p2.x) Y.append(trait.obj.p1.y) Y.append(trait.obj.p2.y) elif isinstance(trait, trts.RayModified): X.append(trait.obj.p1.x) X.append(trait.obj.p2.x) Y.append(trait.obj.p1.y) Y.append(trait.obj.p2.y) elif isinstance(trait, trts.LineModified): X.append(trait.obj.p1.x) X.append(trait.obj.p2.x) Y.append(trait.obj.p1.y) Y.append(trait.obj.p2.y) elif isinstance(trait, trts.ArcModified): xc, yc, rc = trait.obj.center.x, trait.obj.center.y, trait.obj.radius X.append(xc+rc) X.append(xc-rc) Y.append(yc+rc) Y.append(yc+rc) elif isinstance(trait, trts.CircleModified): xc, yc, rc = trait.obj.center.x, trait.obj.center.y, trait.obj.radius X.append(xc+rc) X.append(xc-rc) Y.append(yc+rc) Y.append(yc+rc) self.xMin, self.xMax = np.min(X), np.max(X) self.yMin, self.yMax = np.min(Y), np.max(Y) self.bLines = [ sym.Line( (self.xMin,self.yMin),(self.xMax,self.yMin) ), sym.Line( (self.xMax,self.yMin),(self.xMax,self.yMax) ), sym.Line( (self.xMax,self.yMax),(self.xMin,self.yMax) ), sym.Line( (self.xMin,self.yMax),(self.xMin,self.yMin) ) ]
def test_shapely(self): self.assertEqual( point_line_dist(Point(0, 2), Point(0, 0), Point(1, 1)), LineString([(0, 0), (1, 1)]).project(shapely.geometry.Point(0, 2))) self.assertEqual( sympy.Line(sympy.Point(10, 10), sympy.Point(41, -1)).projection( sympy.Point(0.1, 2.3)).distance(sympy.Point(0.1, 2, 3)), LineString([(0, 0), (1, 1)]).project(shapely.geometry.Point(0, 2)))
def get_l_cusp(hue=0): lab_709, lab_2020, rgb = get_lab_edge(hue) chroma_709 = get_chroma(lab_709) chroma_2020 = get_chroma(lab_2020) bt709_cusp_idx = np.argmax(chroma_709) bt2020_cusp_idx = np.argmax(chroma_2020) bt709_point = sympy.Point(chroma_709[bt709_cusp_idx], lab_709[bt709_cusp_idx, 0]) bt2020_point = sympy.Point(chroma_2020[bt2020_cusp_idx], lab_2020[bt2020_cusp_idx, 0]) chroma_line = sympy.Line(bt709_point, bt2020_point) lightness_line = sympy.Line(sympy.Point(0, 0), sympy.Point(0, 100)) intersection = sympy.intersection(chroma_line, lightness_line)[0].evalf() l_cusp = np.array(intersection) return l_cusp[1]
def get_intersection_primary(out_side_name, in_side_name): """ BT.2020 の Primary と D65 を結ぶ直線と BT.709 の Gamut が交差する点を求める """ bt2020_p, _ = tpg.get_primaries(name=out_side_name) primary, _ = tpg.get_primaries(name=in_side_name) white_point = sympy.Point(tpg.D65_WHITE[0], tpg.D65_WHITE[1]) bt2020_p_points = [ sympy.Point(bt2020_p[x][0], bt2020_p[x][1]) for x in range(3) ] primary_points = [ sympy.Point(primary[x][0], primary[x][1]) for x in range(4) ] bt2020_p_lines = [ sympy.Line(bt2020_p_points[x], white_point) for x in range(3) ] # よく考えたら、どの線と交差するかは gamut の形で決まるんだった…マニュアルで。 # ---------------------------------------------------------------------- primary_lines = [ sympy.Line(primary_points[2], primary_points[3]), sympy.Line(primary_points[1], primary_points[2]), sympy.Line(primary_points[1], primary_points[2]) ] # 交点求める。evalf() して式の評価も済ませておく # ------------------------------------------- intersections = [ sympy.intersection(bt2020_p_lines[x], primary_lines[x])[0].evalf() for x in range(3) ] # 後で扱いやすいように xy の配列に変換しておく # ----------------------------------------- intersections = [[intersections[x].x, intersections[x].y] for x in range(3)] return np.array(intersections)
def plotImage(self, image, oriented_gradients=None): ''' ''' self.xMin = 0 self.xMax = image.shape[1] self.yMin = 0 self.yMax = image.shape[0] self.bLines = [ sym.Line( (self.xMin,self.yMin),(self.xMax,self.yMin) ), sym.Line( (self.xMax,self.yMin),(self.xMax,self.yMax) ), sym.Line( (self.xMax,self.yMax),(self.xMin,self.yMax) ), sym.Line( (self.xMin,self.yMax),(self.xMin,self.yMin) ) ] self.axes.imshow(image, cmap = 'gray', interpolation='nearest')#, origin='lower') if oriented_gradients!=None: self.plot_oriented_gradients(image, oriented_gradients) self.axes.set_xlim([0, np.shape(image)[1]]) self.axes.set_ylim([0, np.shape(image)[0]]) self.draw()
def get_intersection_secondary(out_side_name, in_side_name): """ BT.2020 の Secondary と D65 を結ぶ直線と BT.709 の Gamut が交差する点を求める """ secondary, _ = tpg.get_secondaries(name=out_side_name) primary, _ = tpg.get_primaries(name=in_side_name) white_point = sympy.Point(tpg.D65_WHITE[0], tpg.D65_WHITE[1]) secondary_points = [ sympy.Point(secondary[x][0], secondary[x][1]) for x in range(3) ] primary_points = [ sympy.Point(primary[x][0], primary[x][1]) for x in range(4) ] secondary_lines = [ sympy.Line(secondary_points[x], white_point) for x in range(3) ] primary_lines = [ sympy.Line(primary_points[(x + 2) % 3], primary_points[(x + 3) % 3]) for x in range(3) ] # 交点求める。evalf() して式の評価も済ませておく # ------------------------------------------- intersections = [ sympy.intersection(secondary_lines[x], primary_lines[x])[0].evalf() for x in range(3) ] # 後で扱いやすいように xy の配列に変換しておく # ----------------------------------------- intersections = [[intersections[x].x, intersections[x].y] for x in range(3)] return np.array(intersections)
def make_angles_and_distances(pieces: Dict) -> pd.DataFrame: """Calculates the angles and distances from the vectors and planes. :param pieces: The SSE pieces to calculate the vectors from. """ data = { 'sse': [], 'layer': [], 'angles_layer': [], 'angles_floor': [], 'angles_side': [], 'points_layer': [], 'points_floor': [], 'points_side': [], 'tilted_layer': [], 'tilted_floor': [], 'tilted_side': [] } for layer in sorted(set([x[0] for x in pieces if len(x) == 1])): for sse in [x for x in pieces if len(x) == 3]: if abs(ascii_uppercase.find(layer) - ascii_uppercase.find(sse[0])) <= 1: data['sse'].append(sse) data['layer'].append(layer) for iplane, plane in enumerate(pieces[layer]): if TBcore.get_option('system', 'debug'): sys.stdout.write( 'PDB:{} geometry plane {} vs. sse {}\n'.format( plane, layer, sse)) syPlane = sy.Plane(sy.Point3D(pieces[layer][plane][0]), sy.Point3D(pieces[layer][plane][1]), sy.Point3D(pieces[layer][plane][2])) syLine = sy.Line(pieces[sse]['vector'][0], pieces[sse]['vector'][-1]) syPoint = sy.Point3D(*pieces[sse]['vector'][1]) data[f'angles_{plane}'].append( math.degrees(syPlane.angle_between(syLine))) data[f'points_{plane}'].append( float(syPlane.distance(syPoint))) data[f'tilted_{plane}'].append( float(syPlane.distance(default_plane(iplane)))) return pd.DataFrame(data)
def geometry(): ''' API endpoint used to solve the revist geometry problem ''' data = request.get_json() if "input" in data: data = data["input"] points_arr_shape = [] for i in data['shapeCoordinates']: points_arr_shape.append(sympy.Point(i["x"], i["y"])) line_array_shape = [] for i in range(len(points_arr_shape) - 1): line_array_shape.append( sympy.Segment(points_arr_shape[i], points_arr_shape[i + 1])) line_array_shape.append( sympy.Segment(points_arr_shape[0], points_arr_shape[-1])) line_points = [] for i in data['lineCoordinates']: line_points.append(sympy.Point(i["x"], i["y"])) main_line = sympy.Line(line_points[0], line_points[1]) intersections = [] output = [] for i in line_array_shape: res = sympy.geometry.intersection(i, main_line) if (len(res)): res = list(res[0]) output.append({ "x": round(float(res[0]), 2), "y": round(float(res[1]), 2), }) return jsonify(output)
def reconstruct_room(candidate_virtual_sources, loudspeaker, dist_thresh, shoebox=True): """ This method uses the first-order virtual-sources to reconstruct the room: it processes the candidate virtual sources in the order of increasing distance from the loudspeaker to find the first-order virtual sources and add their planes to the list of half-spaces whose intersection determines the final room. :param candidate_virtual_sources: list of the coordinates of all the individuated virtual sources (it could contain even higher-order virtual sources) :param loudspeaker: x, y, z coordinates of the speaker location in the room :param dist_thresh: distance threshold (epsilon) :param shoebox: boolean to identify if the room is a shoebox :return: list of planes corresponding to the first-order virtual sources """ def combine(s1, s2): """ This method combines the virtual sources s1 and s2 to generate a higher-order virtual source; it is used as a criterion to discard higher-order virtual sources. :param s1: first virtual source coordinates :param s2: second virtual source coordinates :return: the coordinates of the higher order virtual source generated through the combination of s1 and s2 """ # p2 is a point on the hypothetical wall defined by s2, that is, a point on # the median plane between the loudspeaker and s2 p2 = (loudspeaker + s2) / 2 # n2 is the outward pointing unit normal n2 = (loudspeaker - s2) / np.linalg.norm(loudspeaker - s2) return s1 + 2 * np.dot((p2 - s1), n2) * n2 def perpendicular(a): """ This method computes the perpendicular to a given vector. :param a: the given vector :return: the perpendicular vector """ b = np.empty_like(a) b[0] = -a[1] b[1] = a[0] return b # Instantiating the array to contain the distance of each virtual source from the loudspeaker distances_from_speaker = [] # Computing the distances for source in candidate_virtual_sources: distances_from_speaker.append(np.linalg.norm(source - loudspeaker)) # Re-ordering the list of virtual sources according to their distance from the loudspeaker candidate_virtual_sources = np.array(candidate_virtual_sources) sorted_virtual_sources = candidate_virtual_sources[np.array( distances_from_speaker).argsort()][1:] # Initialize the list of planes that constitutes the room room = [] vertices = [] # Initialize the boolean mask to identify the first-order virtual sources deleted = np.array([False] * len(sorted_virtual_sources), dtype=bool) for i in range(len(sorted_virtual_sources)): for j in range(i): for k in range(i): # The following two conditions verify if the current virtual source is a combination of lower order # virtual sources: if so, it is deleted from the available candidates if j != k and k < i: if np.linalg.norm( combine(sorted_virtual_sources[j], sorted_virtual_sources[k]) - sorted_virtual_sources[i]) < dist_thresh: deleted[i] = True # If the room is a "Shoebox" it is possible to exploit geometric properties to filter out # "ghost" image sources from the first order reflections. if shoebox: # Array containing the direction of the axes passing through the source position directions = [] if len(loudspeaker) == 2: x = sp.Line(loudspeaker, loudspeaker + [0, 1]) y = sp.Line(loudspeaker, loudspeaker + [1, 0]) directions.append(x) directions.append(y) elif len(loudspeaker) == 3: planes = [] x = sp.Plane(loudspeaker, [1, 0, 0]) y = sp.Plane(loudspeaker, [0, 1, 0]) z = sp.Plane(loudspeaker, [0, 0, 1]) planes.append(x) planes.append(y) planes.append(z) for i in range(3): for j in range(i): directions.append(planes[i].intersection(planes[j])[0]) for i in range(len(sorted_virtual_sources)): if not deleted[i]: for index, direction in enumerate(directions): if direction.distance(sp.Point( sorted_virtual_sources[i])) < dist_thresh: break else: if index == len(directions) - 1: deleted[i] = True # If the virtual source is not a combination of lower order virtual sources, the corresponding plane # is built and it is added to the room's walls list for i in range(len(sorted_virtual_sources)): if not deleted[i]: # pi is a point on the hypothetical wall defined by si, that is, a point on # the median plane between the loudspeaker and si pi = (loudspeaker + sorted_virtual_sources[i]) / 2 # ni is the outward pointing unit normal ni = (loudspeaker - sorted_virtual_sources[i] ) / np.linalg.norm(loudspeaker - sorted_virtual_sources[i]) plane = {} if len(pi) == 2: ni_perp = perpendicular(ni) pi2 = pi + ni_perp plane = sp.Line(pi, pi2) elif len(pi) == 3: plane = sp.Plane(sp.Point3D(pi), normal_vector=ni) # If the room is empty, we add the first plane to the list of half-spaces whose intersection # determines the final room if len(room) == 0: room.append(plane) else: for wall in room: if len(plane.intersection(wall)) > 0: room.append(plane) break if plane not in room: deleted[i] = True if room[0].ambient_dimension == 2: for wall1 in range(len(room)): for wall2 in range(wall1): if wall1 != wall2: intersections = room[wall2].intersection(room[wall1]) if len(intersections) > 0: for intersection in intersections: if abs(float(intersection.x)) < 100 and abs( float(intersection.y)) < 100: vertices.append(intersection) if room[0].ambient_dimension == 3: planes_intersections = [] for wall1 in range(len(room)): for wall2 in range(wall1): if wall1 != wall2: planes_intersections.append(room[wall2].intersection( room[wall1])) for inter1 in range(len(planes_intersections)): for inter2 in range(inter1): if inter1 != inter2: intersections = planes_intersections[inter2][ 0].intersection(planes_intersections[inter1][0]) if len(intersections) > 0: for intersection in intersections: if abs(float(intersection.x)) < 100 and abs( float(intersection.y)) < 100 and abs( float(intersection.z) ) < 100 and intersection not in vertices: vertices.append(intersection) return room, vertices
def line_to_origin(self) -> S.Line3D: return S.Line(self.source_point, self.source_point.origin)
def bound_traits(trait_list, boundary): ''' this method takes a list of traits and bounds them to boundary. line -> segment note: it only supports boundary [xMin, yMin, xMax, yMax] form. this means, the region of interest (ROI) is always rectangle (parallel to x/y axes) it could be extended to support any kind of region of interest by define the region with a path (e.g. matplotlib) and check if the intersection points are in bound. Since I don't need that genralization, I stick to this simple version ''' xMin, yMin, xMax, yMax = boundary b_lines = [ sym.Line((xMin, yMin), (xMax, yMin)), sym.Line((xMax, yMin), (xMax, yMax)), sym.Line((xMax, yMax), (xMin, yMax)), sym.Line((xMin, yMax), (xMin, yMin)) ] for t_idx in range(len(trait_list) - 1, -1, -1): # the trait before adjustment trait = trait_list[t_idx] if isinstance(trait, (trts.LineModified)): # finding all intersections between trait and boundary lines # the "if" condition is to reject lines: # sym.intersection would return a sym.Line if one of the traits # is the same as one of the boundary lines points = [ p for b_line in b_lines for p in sym.intersection(trait.obj, b_line) if isinstance(p, sym.Point) ] for p_idx in range(len(points) - 1, -1, -1): # checking which points are out of bound wrt. RIO inbound_x = (xMin <= points[p_idx].x <= xMax) inbound_y = (yMin <= points[p_idx].y <= yMax) if not (inbound_x) or not (inbound_y): points.pop(p_idx) if len(points) > 2: # this means some points are coinciding on one corner for p_idx_1 in range(len(points) - 1, -1, -1): for p_idx_2 in range(p_idx_1): if points[p_idx_1].distance( points[p_idx_2]) < np.spacing(10**10): points.pop(p_idx_1) break if len(points) == 2: # in case a trait does not pass through the RIO # insertig the corrected trait back in the list trait = trts.SegmentModified(args=(points[0], points[1])) trait_list[t_idx] = trait else: trait_list.pop(t_idx) else: # the trait is either arc or circle # no need to adjust the trait pass return trait_list
def to_sympy(self): return sympy.Line(self._p1.to_sympy, self.p2.to_sympy)
def leganFunction(event, x, y, flags, params): pointsList = params[0] if (event == cv2.EVENT_LBUTTONDOWN) and ( len(pointsList) < 4): #Left Click and <4 points exist #Draw Point cv2.circle(img, (x, y), 2, (0, 0, 255), cv2.FILLED) #Add to points list pointsList.append((x, y)) print("Point drawn at:" + str(x) + "," + str(y)) print(pointsList) #Factor used in extending line (Change to extend lines more or less) extensionFactor = 50 if len(pointsList) == 2: #If 2 points drawn #Get slope of line slope, yInt = getSlope(pointsList[0], pointsList[1]) if pointsList[0][0] > pointsList[1][0]: extensionFactor = -extensionFactor #Extend Points startX = int(pointsList[0][0] - extensionFactor) startY = int(startX * slope + yInt) newStartPoint = (startX, startY) endX = int(pointsList[1][0] + extensionFactor) endY = int(endX * slope + yInt) newEndPoint = (endX, endY) #Draw Line between extended points cv2.line(img, newStartPoint, newEndPoint, (255, 255, 255), 2) print("Line Drawn at:" + str(newStartPoint) + "," + str(newEndPoint)) elif len(pointsList) == 4: #If 4 points drawn #Get slope of line slope, yInt = getSlope(pointsList[2], pointsList[3]) if pointsList[2][0] > pointsList[3][0]: extensionFactor = -extensionFactor #Extend Points startX = int(pointsList[2][0] - extensionFactor) startY = int(startX * slope + yInt) newStartPoint = (startX, startY) endX = int(pointsList[3][0] + extensionFactor) endY = int(endX * slope + yInt) newEndPoint = (endX, endY) #Draw Line between last two points cv2.line(img, newStartPoint, newEndPoint, (255, 255, 255), 2) print("Line Drawn at:" + str(newStartPoint) + "," + str(newEndPoint)) #Get angle between two lines l1 = sympy.Line(pointsList[0], pointsList[1]) l2 = sympy.Line(pointsList[2], pointsList[3]) #Print angle in degrees print("Legan Angle is: ", math.degrees(l1.smallest_angle_between(l2)))
def edges(self): for i in range(len(self.points) - 1): yield sp.Line(self.points[i], self.points[i + 1]) yield sp.Line(self.points[-1], self.points[0])
def notesToAngle(CutDir1, x1, y1, CutDir2, x2, y2): x3 = 0 y3 = 0 x4 = 0 y4 = 0 if CutDir1 == 0: x3 = x1 y3 = y1 + 1 elif CutDir1 == 1: x3 = x1 y3 = y1 - 1 elif CutDir1 == 2: x3 = x1 - 1 y3 = y1 elif CutDir1 == 3: x3 = x1 + 1 y3 = y1 elif CutDir1 == 4: x3 = x1 - 1 y3 = y1 + 1 elif CutDir1 == 5: x3 = x1 + 1 y3 = y1 + 1 elif CutDir1 == 6: x3 = x1 - 1 y3 = y1 - 1 elif CutDir1 == 7: x3 = x1 + 1 y3 = y1 - 1 elif CutDir1 == 8: x3 = x1 + 1 y3 = y1 + 1 elif CutDir2 == 0: x4 = x2 y4 = y2 + 1 elif CutDir2 == 1: x4 = x2 y4 = y2 - 1 elif CutDir2 == 2: x4 = x2 - 1 y4 = y2 elif CutDir2 == 3: x4 = x2 + 1 y4 = y2 elif CutDir2 == 4: x4 = x2 - 1 y4 = y2 + 1 elif CutDir2 == 5: x4 = x2 + 1 y4 = y2 + 1 elif CutDir2 == 6: x4 = x2 - 1 y4 = y2 - 1 elif CutDir2 == 7: x4 = x2 + 1 y4 = y2 - 1 elif CutDir2 == 8: x4 = x2 + 1 y4 = y2 + 1 try: a = sympy.Line((x1, y1), (x3, y3)) b = sympy.Line((x2, y2), (x4, y4)) angle = a.smallest_angle_between(b) except ValueError: angle = 0 return angle
theta = np.linspace(0, 2 * np.pi, 4, endpoint=False) xc, yc, rc = trait.obj.center.x, trait.obj.center.y, trait.obj.radius x.extend(xc + rc * np.cos(theta)) y.extend(yc + rc * np.sin(theta)) elif isinstance(trait.obj, sym.Line): x.extend([trait.obj.p1.x, trait.obj.p2.x]) y.extend([trait.obj.p1.y, trait.obj.p2.y]) if len(x) != 0: xMin = np.float(min([x_.evalf() for x_ in x])) xMax = np.float(max([x_.evalf() for x_ in x])) yMin = np.float(min([y_.evalf() for y_ in y])) yMax = np.float(max([y_.evalf() for y_ in y])) bLines = [ sym.Line((xMin, yMin), (xMax, yMin)), sym.Line((xMax, yMin), (xMax, yMax)), sym.Line((xMax, yMax), (xMin, yMax)), sym.Line((xMin, yMax), (xMin, yMin)) ] ################################################################################ def plot_traits(axis, traits, clrs=None, alph=None): if clrs is None: clrs = {'cir': 'b', 'arc': 'b', 'lin': 'r', 'seg': 'g', 'ray': 'g'} if alph is None: alph = {'cir': 1., 'arc': 1., 'lin': 1., 'seg': 1., 'ray': 1.} for idx, trait in enumerate(traits):