def test_dot_product(): """Check dot product of two Vectors.""" Ω = Point(0, 0, 'Ω') A = Point(1, 1, 'A') with pytest.raises(TypeError) as excinfo: Vector(0, 1).dot(Bipoint(Ω, A)) assert str(excinfo.value) == 'Can only calculate the dot product of a '\ 'Vector by another Vector. '\ 'Found Bipoint(Point Ω(0, 0), Point A(1, 1)) instead.' u = Vector(1, 1) v = Vector(3, -7) assert u.dot(v) == -4 u = Vector(2, 5, -7) v = Vector(3, -7, 2) assert u.dot(v) == -43
def __init__(self, point, vertex, point_or_measure, decoration=None, mark_right=False, second_point_name='auto', label=None, color=None, thickness='thick', armspoints=None, label_vertex=False, draw_vertex=False, label_armspoints=False, draw_armspoints=False, label_endpoints=False, draw_endpoints=False, naming_mode='from_endpoints', decoration2=None): """ :param point: a Point of an arm of the Angle :type point: Point :param vertex: the Angle's vertex :type vertex: Point :param point_or_measure: either a Point of the other arm of the Angle, or the measure of the Angle :type point_or_measure: Point or number :param decoration: the decoration of the Angle :type decoration: None or AngleDecoration :param mark_right: to tell whether to mark the angle as a right angle :type mark_right: bool :param second_point_name: Only used if point_or_measure is a measure, this is the name of the 2d arm's Point. If set to 'auto', then the name of the first Point will be used, concatenated to a '. :type second_point_name: str :param thickness: the Angle's arms' thickness. Available values are TikZ's ones. :type thickness: str :param color: the color of the Angle's arms. :type color: str :param naming_mode: how to build the name. Possible modes are: 'from_endpoints', 'from_armspoints', 'from_vertex'. Note that if no armspoints are defined, then trying to get the Angle.name will raise an error :type naming_mode: str """ self.color = color self.thickness = thickness self.naming_mode = naming_mode self.decoration = decoration self.decoration2 = decoration2 # The label must be set *after* the possible decoration, because it # will actually be handled by self.decoration if (self.decoration is None or self.decoration.label in [None, 'default']): self.label = label else: if label is not None: raise ValueError('The label has been set twice, as Angle\'s ' 'keyword argument ({}) and as its ' 'AngleDecoration\'s keyword argument ({}).' .format(repr(label), repr(self.decoration.label_value))) self.mark_right = mark_right self.label_vertex = label_vertex self.label_endpoints = label_endpoints self.draw_endpoints = draw_endpoints self.label_armspoints = label_armspoints self.draw_armspoints = draw_armspoints self.draw_vertex = draw_vertex if not (isinstance(point, Point) and isinstance(vertex, Point) and (isinstance(point_or_measure, Point) or is_number(point_or_measure))): raise TypeError('Three Points, or two Points and the measure of ' 'the angle are required to build an Angle. ' 'Found instead: {}, {} and {}.' .format(type(point), type(vertex), type(point_or_measure))) self._points = [point, vertex] if isinstance(point_or_measure, Point): self._points.append(point_or_measure) else: self._points.append(point.rotate(vertex, point_or_measure, rename=second_point_name)) if any([p.three_dimensional for p in self._points]): self._three_dimensional = True else: self._three_dimensional = False # Measure of the angle: if self._three_dimensional: u = Vector(self.points[1], self.points[0]) v = Vector(self.points[1], self.points[2]) self._measure = Number(str(degrees(atan2(u.cross(v).length, u.dot(v))))) else: # 2D angles measure p0 = Point(self._points[0].x - self._points[1].x, self._points[0].y - self._points[1].y, None) p2 = Point(self._points[2].x - self._points[1].x, self._points[2].y - self._points[1].y, None) α0 = Number(str(degrees(atan2(p0.y, p0.x)))) α2 = Number(str(degrees(atan2(p2.y, p2.x)))) self._measure = α2 - α0 if self._measure < 0: self._measure += 360 # This is not like the matching Triangle! if shoelace_formula(*self.points) > 0: self.winding = 'clockwise' else: self.winding = 'anticlockwise' arm0 = Bipoint(self._points[1], self._points[0]) arm1 = Bipoint(self._points[1], self._points[2]) self._arms = [arm0, arm1] self.armspoints = armspoints # Only 2D: labels positioning if not self.three_dimensional: # Vertex' label positioning bisector = Vector(self._points[0], self.vertex)\ .bisector(Vector(self._points[2], self.vertex), new_endpoint_name=None) try: self._points[1].label_position = \ tikz_approx_position(bisector.slope360) except ZeroVector: self._points[1].label_position = \ tikz_approx_position( Bipoint(self.vertex, self._points[0].rotate(self.vertex, -90, rename=None) ).slope360) # Endpoints labels positioning direction = 1 if self.winding == 'anticlockwise' else -1 self.endpoints[0].label_position = \ tikz_approx_position(arm0.slope360 - direction * 55) self.endpoints[1].label_position = \ tikz_approx_position(arm1.slope360 + direction * 55)