def __init__(self, M1, M2, tangent): self.M1 = M1.copy() self.M2 = M2.copy() self.tangent = tangent.copy() self.C = self.center() self.r = self.radius() self.theta1 = Vector_M1M2(self.C, self.M1).theta_x() self.theta2 = Vector_M1M2(self.C, self.M2).theta_x() self.ccw = self._get_ccw()
def normal(self, normalized=False): """Return a normal to the segment. Args: normalized (bool): if True, return a unit vector. Returns: :class:`~.elements.vector.Vector` """ return Vector_M1M2(self.M1, self.M2).normal(normalized=normalized)
def intersection(self, other, sign_of_s=0): """Intersections of the segment with another element. Args: other (Line): another element (as of v0.18, it must be a Line) sign_of_s (int): if `sign_of_s !=0`, consider other as a half line. i.e. `s_other` must have the same sign as `sign_of_s` or intersection will be empty Returns: :obj:`list` of :class:`.Intersection`: list of intersections """ if isinstance(other, Line): result = Line(self.M1, Vector_M1M2(self.M1, self.M2)).intersection(other, sign_of_s) if not result: # no intersection return [] else: # there should be only one intersection # split the sequence unpacking in two chunks for # kdevelop semantic analysis intersection, = result Mi, s, eN, eT = intersection if abs(self.M2.x - self.M1.x) > abs(self.M2.y - self.M1.y): # M1M2 closer to x axis if (self.M2.x > self.M1.x): # M2 to the right of M1 if (Mi.x < self.M1.x) or (Mi.x > self.M2.x): # outside return [] else: # M2 to the left of M1 if (Mi.x < self.M2.x) or (Mi.x > self.M1.x): # outside return [] else: # M1M2 closer to y axis if (self.M2.y > self.M1.y): # M2 above M1 if (Mi.y < self.M1.y) or (Mi.y > self.M2.y): # outside return [] else: # M2 below M1 if (Mi.y < self.M2.y) or (Mi.y > self.M1.y): # outside return [] else: raise NotImplementedError( "intersection between Line and {}".format(type(other))) return result
def intersection(self, other, sign_of_s=0): """Intersections of the arc with another element. Args: other (Line): another element (as of v0.18, it must be a Line) sign_of_s (int): if `sign_of_s !=0`, consider other as a half line. i.e. `s_other` must have the same sign as `sign_of_s` or intersection will be empty Returns: :obj:`list` of :class:`.Intersection`: list of intersections """ result = [] if isinstance(other, Line): s_list = [] a = other.u.x**2 + other.u.y**2 if a != 0: b = (other.u.x * (other.p.x - self.C.x) + other.u.y * (other.p.y - self.C.y)) c = ((other.p.x - self.C.x)**2 + (other.p.y - self.C.y)**2 - self.r**2) # reduced discriminant delta = b**2 - a * c # compute roots if delta > 0: # this way is numerically more stable (?) if b >= 0: q = -b - sqrt(delta) else: q = -b + sqrt(delta) # two roots s1 = q / a s2 = c / q s_list.extend([s1, s2]) elif delta == 0: # one root s = -b / a s_list.append(s) for s in s_list: # intersection point M = other.point(s) if (M in self) and (s * sign_of_s >= 0): # normal is \vec{CM}/CM eN = Vector_M1M2(self.C, M).normalize() # tangent is orthogonal to normal for a circle eT = eN.normal(normalized=True) result.append(Intersection(M, s, eN, eT)) else: raise NotImplementedError( "intersection between Line and {}".format(type(other))) return result
def center(self): """Return the arc center.""" # middle of the chord Mm = (self.M1 + self.M2) * 0.5 # normal to the chord Vch = Vector_M1M2(self.M1, self.M2).normal() # normal to the tangent Vtg = self.tangent.normal() # normally there should be only one intersection # there should be only one intersection intersection, = Line(Mm, Vch).intersection(Line(self.M1, Vtg)) C = intersection.p return C
def __contains__(self, M): """Return `True` if the point M belongs to the arc sector. Distances are not checked. """ theta_i = Vector_M1M2(self.C, M).theta_x() if self.theta2 < self.theta1: if self.theta2 < theta_i < self.theta1: return not self.ccw else: return self.ccw else: if self.theta1 < theta_i < self.theta2: return self.ccw else: return not self.ccw
def _get_ccw(self): """Return true if the arc goes from M1 to M2 ccw.""" CM1 = Vector_M1M2(self.C, self.M1) return ((CM1.x * self.tangent.y - CM1.y * self.tangent.x) > 0)
def radius(self): """Return the arc radius of curvature.""" return Vector_M1M2(self.M1, self.center()).norm()