class Color(StrongPropertyInitializer): """Defines a color in terms of a name and RGB values""" name = StringProperty() red = NumberProperty(default=0.0, restriction=RESTRICT_FRACTION) green = NumberProperty(default=0.0, restriction=RESTRICT_FRACTION) blue = NumberProperty(default=0.0, restriction=RESTRICT_FRACTION) def __init__(self, red=0.0, green=0.0, blue=0.0, **kwargs): super(Color, self).__init__(red=red, green=green, blue=blue, **kwargs) def rgb_tuple(self): return (self.red, self.green, self.blue) def numpy_array(self): import numpy return numpy.array([self.red, self.green, self.blue]) def set(self, red, green, blue): self.red = red self.green = green self.blue = blue def html_string(self): return "#%02X%02X%02X" % (self.red * 255, self.green * 255, self.blue * 255) def __eq__(self, other): return other.red == self.red and other.green == self.green and other.blue == self.blue def __neq__(self, other): return other.red != self.red or other.green != self.green or other.blue != self.blue def __str__(self): return self.name
class ShapeGrow(__ShapeModifier__): """ generates a shape with uniformly grows """ offset = DefinitionProperty(fdef_name="define_offset") amount = NumberProperty(required=True) def __init__(self, original_shape, amount, **kwargs): super(ShapeGrow, self).__init__(original_shape=original_shape, amount=amount, **kwargs) def is_closed(self): return self.original_shape.is_closed() closed = FunctionProperty(is_closed, Shape.set_closed) def define_offset(self): o = self.original_shape.orientation() * self.amount return o def define_points(self, pts): original = Shape(self.original_shape).remove_straight_angles() if len(original) <= 1: return a2 = original.angles_rad() * 0.5 a1 = roll(a2, 1) a_plus = a2 + a1 cos_a_min = cos(a2 - a1) offsets = column_stack((-sin(a_plus) / cos_a_min, cos(a_plus) / cos_a_min)) * (self.offset) # compute offsets from each point pts = (original.points + offsets) return pts
class ShapeOffset(__ShapeStartEndAngle__): """ generates a shape with a given offset from its original shape""" offset = NumberProperty(required=True) def __init__(self, original_shape, offset, **kwargs): super(ShapeOffset, self).__init__(original_shape=original_shape, offset=offset, **kwargs) def define_points(self, pts): original = self.__get_original_shape_without_straight_angles__() if len(original) <= 1: return a2 = original.angles_rad() * 0.5 a1 = roll(a2, 1) if original.closed: a2[-1] = a2[0] a1[0] = a1[-1] else: a2[-1] = self.end_face_angle * DEG2RAD - a2[-2] a1[0] = self.start_face_angle * DEG2RAD - a1[1] a_plus = a2 + a1 cos_a_min = cos(a2 - a1) offsets = column_stack((-sin(a_plus) / cos_a_min, cos(a_plus) / cos_a_min)) * (self.offset) # compute offsets from each point pts = (original.points + offsets) return pts
class __ARef1dElement__(ARef): period = DefinitionProperty(fdef_name="define_period") n_o_periods = DefinitionProperty(fdef_name="define_n_o_periods") period_1d = NumberProperty(default=1.0, restriction=RESTRICT_NONZERO) n_o_periods_1d = IntProperty(default=1, restriction=RESTRICT_POSITIVE) def __init__(self, reference, origin, period_1d, n_o_periods_1d, transformation=None, **kwargs): kwargs["period"] = SUPPRESSED kwargs["n_o_periods"] = SUPPRESSED super(__ARef1dElement__, self).__init__(reference=reference, origin=origin, period_1d=period_1d, n_o_periods_1d=n_o_periods_1d, transformation=transformation, **kwargs) def is_empty(self): return __RefElement__.is_empty(self) or (self.n_o_periods_1d == 0)
class CircuitModel(twoshape.CoreCladdingShapeWaveguide.CircuitModel): phase_error = NumberProperty() def _default_phase_error(self): if not hasattr(self.template, 'phase_error_sigma'): import warnings warnings.warn( 'Trace template has no phase_error_sigma variable, setting it to 0' ) return 0 phase_error_sigma = self.template.phase_error_sigma if phase_error_sigma == 0.0: return 0.0 return np.random.normal(0.0, phase_error_sigma) def _generate_model(self): from aeponyx.compactmodels import WGPhaseErrorCompactModel model = WGPhaseErrorCompactModel( n_g=self.template.n_g, n_eff=self.template.n_eff, center_wavelength=self.template.center_wavelength, length=self.length, phase_error=self.phase_error) return model
class NoDistortTransform(GenericNoDistortTransform): """ A homothetic transformation that does not distort the item it is applied to (angle conservation) The transform is defined by - a mirror around the x-axis - a scaling with respect to the origin - a rotation around the origin - a translation it is also possible to set absolute magnification and rotation, which means that subsequent transformations will not affect the angle and size any further """ # FIXME : Use transformation matrix which is computed once (and cached) def __init__(self, translation = (0.0, 0.0), rotation = 0.0, magnification = 1.0, v_mirror = False, absolute_magnification = False, absolute_rotation = False, **kwargs): # note: translation is no part of gdsII transform. It should be taken into account while writing the file super(NoDistortTransform, self).__init__( translation = translation, rotation = rotation, magnification = magnification, v_mirror = v_mirror, absolute_magnification = absolute_magnification, absolute_rotation =absolute_rotation, **kwargs) translation = Coord2Property("__translation__", default = (0.0, 0.0)) """ the translation coordinate """ #def get_rotation (self): return self.rotation def set_rotation(self, value): self.__rotation__ = value % 360.0 if value % 90.0 == 0.0: # make sure sine and cosine are really zero when needed! if self.__rotation__ == 0.0: self.__ca__ = 1.0 self.__sa__ = 0.0 elif self.__rotation__ == 90.0: self.__ca__ = 0.0 self.__sa__ = 1.0 elif self.__rotation__ == 180.0: self.__ca__ = -1.0 self.__sa__ = 0.0 elif self.__rotation__ == 270.0: self.__ca__ = 0.0 self.__sa__ = -1.0 else: self.__ca__ = cos(value * DEG2RAD) self.__sa__ = sin(value * DEG2RAD) rotation = SetFunctionProperty("__rotation__", set_rotation, default=0.0) """ the rotation around the origin """ magnification = NumberProperty("__magnification__", restriction = RESTRICT_NONZERO, default = 1.0) """ the magnification factor """ v_mirror = BoolProperty("__v_mirror__", default = False) """ the vertical mirror """ flip = v_mirror #""" set absolute magnification on or off""" absolute_magnification = BoolProperty("__absolute_magnification__", default = False) #""" set absolute rotation on or off""" absolute_rotation = BoolProperty("__absolute_rotation__", default = False) def __make_simple__(self): """ internal use: reduces special subclasses to this generic type """ # if you change special types, they should revert to generic type self.__class__ = NoDistortTransform def __translate__(self, coord): """ internal use: applies translation to a coordinate """ return Coord2(coord[0] + self.translation.x, coord[1] + self.translation.y) def __rotate__(self, coord): """ internal use: applies rotation to a coordinate """ return Coord2(coord[0] * self.__ca__ - coord[1] * self.__sa__, coord[0] * self.__sa__ + coord[1] * self.__ca__) def __magnify__(self, coord): """ internal use: applies magnification to a coordinate """ return Coord2(coord[0] * self.magnification, coord[1] * self.magnification) def __v_flip__(self, coord): """ internal use: applies v_mirror to a coordinate """ if self.v_mirror: return Coord2(coord[0], -coord[1]) else: return Coord2(coord[0], coord[1]) def __inv_translate__(self, coord): """ internal use: applies reverse translation to a coordinate """ return Coord2(coord[0] - self.translation.x, coord[1] - self.translation.y) def __inv_rotate__(self, coord): """ internal use: applies reverse rotation to a coordinate """ return Coord2(coord[0] * self.__ca__ + coord[1] * self.__sa__, - coord[0] * self.__sa__ + coord[1] * self.__ca__) def __inv_magnify__(self, coord): """ internal use: applies reverse magnification to a coordinate """ return Coord2(coord[0] / self.magnification, coord[1] / self.magnification) def __inv_v_flip__(self, coord): """ internal use: applies reverse v_mirror to a coordinate """ if self.v_mirror: return Coord2(coord[0], - coord[1]) else: return Coord2(coord[0], coord[1]) def __translate3__(self, coord): """ internal use: applies translation to a 3d coordinate """ return Coord3(coord[0] + self.translation.x, coord[1] + self.translation.y, coord[2]) def __rotate3__(self, coord): """ internal use: applies rotation to a 3d coordinate """ return Coord3(coord[0] * self.__ca__ - coord[1] * self.__sa__, coord[0] * self.__sa__ + coord[1] * self.__ca__, coord[2]) def __magnify3__(self, coord): """ internal use: applies magnification to a 3d coordinate """ return Coord3(coord[0] * self.magnification, coord[1] * self.magnification, coord[2]) def __v_flip3__(self, coord): """ internal use: applies v_mirror to a 3d coordinate """ if self.v_mirror: return Coord3(coord[0], -coord[1], coord[2]) else: return Coord3(coord[0], coord[1], coord[2]) def __inv_translate3__(self, coord): """ internal use: applies reverse translation to a 3d coordinate """ return Coord3(coord[0] - self.translation.x, coord[1] - self.translation.y, coord[2]) def __inv_rotate3__(self, coord): """ internal use: applies reverse rotation to a 3d coordinate """ return Coord3(coord[0] * self.__ca__ + coord[1] * self.__sa__, - coord[0] * self.__sa__ + coord[1] * self.__ca__, coord[2]) def __inv_magnify3__(self, coord): """ internal use: applies reverse magnification to a 3d coordinate """ return Coord3(coord[0] / self.magnification, coord[1] / self.magnification, coord[2]) def __inv_v_flip3__(self, coord): """ internal use: applies reverse v_mirror to a 3d coordinate """ if self.v_mirror: return Coord3(coord[0], - coord[1], coord[2]) else: return Coord3(coord[0], coord[1], coord[2]) def __translate_array__(self, coords): """ internal use: applies translation to a numpy array """ coords += numpy.array([self.translation.x, self.translation.y]) return coords def __rotate_array__(self, coords): """ internal use: applies rotation to a numpy array """ x_a = numpy.array([self.__ca__, -self.__sa__]) y_a = numpy.array([self.__sa__, self.__ca__]) coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1)))) return coords def __magnify_array__(self, coords): """ internal use: applies magnification to a numpy array """ coords *= numpy.array([self.magnification, self.magnification]) return coords def __v_flip_array__(self, coords): """ internal use: applies v_mirror to a numpy array """ coords *= (numpy.array([False, self.v_mirror]) * -2.0 + 1.0) return coords def __inv_translate_array__(self, coords): """ internal use: applies reverse translation to a numpy array """ coords -= numpy.array([self.translation.x, self.translation.y]) return coords def __inv_rotate_array__(self, coords): """ internal use: applies reverse rotation to a numpy array """ x_a = array([self.__ca__, self.__sa__]) y_a = array([-self.__sa__, self.__ca__]) coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1)))) return coords def __inv_magnify_array__(self, coords): """ internal use: applies reverse magnification to a numpy array """ coords *= numpy.array([1.0 / self.magnification, 1.0 / self.magnification]) return coords def __inv_v_flip_array__(self, coords): """ internal use: applies reverse v_mirror to a numpy array """ coords *= numpy.array([False, self.v_mirror]) * (-2.0) + 1.0 return coords def __translate_array3__(self, coords): """ internal use: applies translation to a numpy array """ coords += numpy.array([self.translation.x, self.translation.y, 0.0]) return coords def __rotate_array3__(self, coords): """ internal use: applies rotation to a numpy array """ x_a = numpy.array([self.__ca__, -self.__sa__, 0]) y_a = numpy.array([self.__sa__, self.__ca__, 0]) z_a = numpy.array([0, 0, 1.0]) coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1), numpy.sum(coords * z_a, 1)))) return coords def __magnify_array3__(self, coords): """ internal use: applies magnification to a numpy array """ coords *= numpy.array([self.magnification, self.magnification, 1.0]) return coords def __v_flip_array3__(self, coords): """ internal use: applies v_mirror to a numpy array """ coords *= (numpy.array([False, self.v_mirror, False]) * -2.0 + 1.0) return coords def __inv_translate_array3__(self, coords): """ internal use: applies reverse translation to a numpy array """ coords -= numpy.array([self.translation.x, self.translation.y, 0.0]) return coords def __inv_rotate_array3__(self, coords): """ internal use: applies reverse rotation to a numpy array """ x_a = array([self.__ca__, self.__sa__, 0.0]) y_a = array([-self.__sa__, self.__ca__, 0.0]) z_a = numpy.array([0, 0, 1.0]) coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1), numpy.sum(coords * z_a, 1)))) return coords def __inv_magnify_array3__(self, coords): """ internal use: applies reverse magnification to a numpy array """ coords *= numpy.array([1.0 / self.magnification, 1.0 / self.magnification, 1.0]) return coords def __inv_v_flip_array3__(self, coords): """ internal use: applies reverse v_mirror to a numpy array """ coords *= numpy.array([False, self.v_mirror, False]) * (-2.0) + 1.0 return coords def apply_to_coord(self, coord): """ applies transformation to a coordinate """ # this could be speeded up # Check the east order coord = self.__v_flip__(coord)# first flip coord = self.__rotate__(coord)# then magnify coord = self.__magnify__(coord)# then rotate coord = self.__translate__(coord) # finally translate return coord def reverse_on_coord(self, coord): """ applies reverse transformation to a coordinate """ # this could be speeded up # Check the right order coord = self.__inv_translate__(coord) # finally translate coord = self.__inv_magnify__(coord)# then rotate coord = self.__inv_rotate__(coord)# then magtnify coord = self.__inv_v_flip__(coord)# first flip return coord def apply_to_array(self, coords): """ internal use: applies transformation to a numpy array""" # this could be speeded up # Check the right order coords = self.__v_flip_array__(coords)# first flip coords = self.__rotate_array__(coords)# then rotate coords = self.__magnify_array__(coords)# then magnify coords = self.__translate_array__(coords) # finally translate return coords def reverse_on_array(self, coord): """ internal use: applies reverse transformation to a numpy array """ # this could be speeded up # Check the right order coords = self.__inv_translate_array__(coords) # finally translate coords = self.__inv_magnify_array__(coords)# then magnify coords = self.__inv_rotate_array__(coords)# then rotate coords = self.__inv_v_flip_array__(coords)# first flip return coords def apply_to_coord3(self, coord): """ applies transformation to a coordinate """ # this could be speeded up # Check the east order coord = self.__v_flip3__(coord)# first flip coord = self.__rotate3__(coord)# then magnify coord = self.__magnify3__(coord)# then rotate coord = self.__translate3__(coord) # finally translate return coord def reverse_on_coord3(self, coord): """ applies reverse transformation to a coordinate """ # this could be speeded up # Check the right order coord = self.__inv_translate3__(coord) # finally translate coord = self.__inv_magnify3__(coord)# then rotate coord = self.__inv_rotate3__(coord)# then magtnify coord = self.__inv_v_flip3__(coord)# first flip return coord def apply_to_array3(self, coords): """ internal use: applies transformation to a numpy array""" # this could be speeded up # Check the right order coords = self.__v_flip_array3__(coords)# first flip coords = self.__rotate_array3__(coords)# then rotate coords = self.__magnify_array3__(coords)# then magnify coords = self.__translate_array3__(coords) # finally translate return coords def reverse_on_array3(self, coord): """ internal use: applies reverse transformation to a numpy array """ # this could be speeded up # Check the right order coords = self.__inv_translate_array3__(coords) # finally translate coords = self.__inv_magnify_array3__(coords)# then magnify coords = self.__inv_rotate_array3__(coords)# then rotate coords = self.__inv_v_flip_array3__(coords)# first flip return coords def apply_to_angle_deg(self, angle): """ applies transformation to an absolute angle (degrees) """ a = angle if self.v_mirror: a = -a a += self.rotation return a % 360.0 def reverse_on_angle_deg(self, angle): """ applies reverse transformation to an absolute angle (degrees)""" a = angle - self.rotation if self.v_mirror: a = -a return a % 360.0 def apply_to_angle_rad(self, angle): """ applies transformation to an absolute angle (radians) """ a = angle if self.v_mirror: a = -a a += self.rotation * DEG2RAD return a % (2 * pi) def reverse_on_angle_rad(self, angle): """ applies reverse transformation to an absolute angle (radians) """ a = angle - self.rotation * DE2RAD if self.v_mirror: a = -a return a % (2 * pi) def apply_to_length(self, length): """ applies transformation to a distance """ return length * self.magnification def reverse_on_length(self, length): """ applies reverse transformation to a distance """ return length / self.magnification def __neg__(self): """ returns the reverse transformation """ from .translation import Translation from .rotation import Rotation from .magnification import Magnification from .mirror import VMirror T = Translation(- self.translation) + Magnification((0.0, 0.0), 1 / self.magnification) + Rotation((0.0, 0.0), -self.rotation) if self.v_mirror: T += VMirror(0.0) return T def __sub__(self, other): """ returns the concatenation of this transform and the reverse of other """ if other is None: return copy.deepcopy(self) if not isinstance(other, __ReversibleTransform__): raise TypeError("Cannot subtract an irreversible transform") return self.__add__(-other) def __isub__(self, other): """ concatenates the reverse of other to this transform """ if other is None: return self if not isinstance(other, __ReversibleTransform__): raise TypeError("Cannot subtract an irreversible transform") return self.__iadd__(self, -other) def __add__(self, other): """ returns the concatenation of this transform and other """ # performs transformation "other" after "self" and returns resulting transform if other is None: return copy.deepcopy(self) if isinstance(other, NoDistortTransform): T = NoDistortTransform() if self.absolute_magnification: M1 = 1.0 else: M1 = other.magnification T.magnification = self.magnification * M1 #flip signs if other.v_mirror: s_1 = -1 else: s_1 = 1 if not self.absolute_rotation: T.rotation = s_1 * self.rotation + other.rotation ca = other.__ca__ sa = other.__sa__ else: T.rotation = s_1 * self.rotation ca = 1.0 sa = 0.0 # tricky part: translation T.translation = Coord2(other.translation.x + ca * self.translation.x * M1 - s_1 * sa * self.translation.y * M1, other.translation.y + sa * self.translation.x * M1 + s_1 * ca * self.translation.y * M1) T.absolute_rotation = self.absolute_rotation or other.absolute_rotation T.absolute_magnification = self.absolute_magnification or other.absolute_magnification T.v_mirror = (not self.v_mirror == other.v_mirror) else: T = Transform.__add__(self, other) return T def __iadd__(self, other): """ concatenates other to this transform """ if other is None: return self # performs transformation other after self and returns self if isinstance(other, NoDistortTransform): # tricky part: translation if self.absolute_magnification: self.magnification = self.magnification * other.magnification M1 = 1 else: M1 = other.magnification #flip signs if other.v_mirror: s_1 = -1 else: s_1 = 1 if not self.absolute_rotation: self.rotation = s_1 * self.rotation + other.rotation ca = other.__ca__ sa = other.__sa__ else: self.rotation = s_1 * self.rotation ca = 1 sa = 0 # tricky part: translation self.translation = (other.translation.x + ca * self.translation.x * M1 - s_1 * sa * self.translation.y * M1, other.translation.y + sa * self.translation.x * M1 + s_1 * ca * self.translation.y * M1) self.absolute_rotation = self.absolute_rotation or other.absolute_rotation self.absolute_magnification = self.absolute_magnification or other.absolute_magnification self.v_mirror = (not self.v_mirror == other.v_mirror) else: raise TypeError("Error: Cannot perform += operation for NoDistortTransform and other transform of type " + str(type(other))) return self def __eq__(self, other): """ check if the transforms do the same thing """ if other is None: return self.is_identity() if not isinstance(other, NoDistortTransform): return False return ((self.rotation == other.rotation) and (self.translation == other.translation) and (self.v_mirror == other.v_mirror) and (self.magnification == other.magnification) and (self.absolute_rotation == other.absolute_rotation) and (self.absolute_magnification == other.absolute_magnification) ) def __ne__(self, other): """ checks if the transforms do different things """ if other is None: return not self.is_identity() if not isinstance(other, NoDistortTransform): return False return ((self.rotation != other.rotation) or (self.translation != other.translation) or (self.v_mirror != other.v_mirror) or (self.magnification != other.magnification) or (self.absolute_rotation != other.absolute_rotation) or (self.absolute_magnification != other.absolute_magnification) ) def is_identity(self): """ returns True if the transformation does nothing """ return ((self.rotation == 0.0) and (self.translation.x == 0.0) and (self.translation.y == 0.0) and not (self.v_mirror) and (self.magnification == 1.0) ) def is_isometric(self): """ returns True if the transformation conserves angles and distances """ return self.magnification == 1.0 def is_homothetic(self): """ returns True if the transformation conserves angles """ return True def is_orthogonal(self): """ returns True if the transformation does only rotate on 90degree angles """ return (self.rotation % 90.0) == 0.0 def is_octogonal(self): """ returns True if the transformation does only rotate on 45degree angles """ return (self.rotation % 45.0) == 0.0 def id_string(self): """ gives a hash of the transform (for naming purposes) """ return str(hash("R" + str(int(self.rotation * 10000)) + "T" + str(int(self.translation[0] * 1000)) + "_" + str(int(self.translation[1] * 1000)) + "M" + str(int(self.magnification * 1000)) + "V" + str(self.v_mirror) + "AM" + str(self.absolute_magnification) + "AR" + str(self.absolute_rotation) )) def __str__(self): """ gives a string representing the transform """ return "R=%s-T=%s-M=%s-V=%s-AM=%s-AR=%s" % (str(int(self.rotation * 10000)), str(int(self.translation[0] * 1000)) + "_" + str(int(self.translation[1] * 1000)), str(int(self.magnification * 1000)), str(self.v_mirror), str(self.absolute_magnification), str(self.absolute_rotation))
class StraightLine(transformable.Transformable, StrongPropertyInitializer): """ creates a line ax + by + c = 0 """ a = NumberProperty(required=True) b = NumberProperty(required=True) c = NumberProperty(required=True) def __init__(self, a, b, c, **kwargs): super(StraightLine, self).__init__(a=a, b=b, c=c, **kwargs) def get_slope(self): if self.b == 0: return None return -self.a / self.b slope = property(get_slope, doc="gives slope (tangent) of the line" "") def is_on_line(self, coordinate): """ returns True if point is on line """ return abs(self.a * coordinate[0] + self.b * coordinate[1] + self.c) < 1E-10 def get_angle_rad(self): return atan2(-self.a, self.b) angle_rad = property(get_angle_rad, doc="gives angle of line (in radians)") def get_angle_deg(self): return RAD2DEG * self.angle_rad angle_deg = property(get_angle_deg, doc="gives angle of line (in radians)") def get_y_intercept(self): if self.b == 0.0: return None return -self.c / -self.b y_intercept = property( get_y_intercept, doc="gives y-intercept of line (None if parallel to Y)") def get_x_intercept(self): if self.a == 0.0: return None return -self.c / -self.a x_intercept = property( get_x_intercept, doc="gives x-intercept of line (None if parallel to X)") def distance(self, coordinate): """ gives distance of point to line """ return abs(self.a * coordinate[0] + self.b * coordinate[1] + self.c ) / sqrt(self.a**2 + self.b**2) def intersection(self, line): """ gives intersection of line with other line """ if (self.b * line.a - self.a * line.b) == 0.0: return None return Coord2(-(self.b * line.c - line.b * self.c) / (self.b * line.a - self.a * line.b), (self.a * line.c - line.a * self.c) / (self.b * line.a - self.a * line.b)) def closest_point(self, point): """ gives closest point on line """ line2 = straight_line_from_point_angle(point, self.angle_deg + 90.0) return self.intersection(line2) def is_on_same_side(self, point1, point2): """ returns True is both points are on the same side of the line """ return numpy.sign(self.a * point1[0] + self.b * point1[1] + self.c) == numpy.sign( self.a * point2[0] + self.b * point2[1] + self.c) def is_parallel(self, other): """ returns True is lines are parallel """ return abs(self.a * other.b - self.b * other.a) < 1E-10 def __eq__(self, other): return abs(self.a * other.b - self.b * other.a) < 1E-10 and abs( self.c * other.b - self.b * other.c) < 1E-10 and abs( self.a * other.c - self.c * other.a) < 1E-10 def __ne__(self, other): return (not self.__eq__(other)) def __get_2_points__(self): """ returns 2 points on the line. If a horizontal or vertical, it returns one point on the axis, and another 1.0 further. If the line is oblique, it returns the intersects with the axes """ from .shape import Shape if b == 0: return Shape( [Coord2(-self.c / self.a, 0.0), Coord2(-self.c / self.a, 1.0)]) elif a == 0: return Shape( [Coord2(0.0, -self.c / self.b), Coord2(1.0, -self.c / self.b)]) else: return Shape( [Coord2(-self.c / self.a, 0.0), Coord2(0.0, -self.c / self.b)]) def transform(self, transformation): """ transforms the straight line with a given transformation """ p = self.__get_2_points__().transform(transformation) self.a = y2 - y1 self.b = x1 - x2 self.c = (x2 - x1) * y1 - (y2 - y1) * x1 def transform_copy(self, transformation): """ transforms a copy of the straight line with a given transformation """ p = self.__get_2_points__().transform(transformation) return straight_line_from_two_points(p[0], p[1])