def self_intersects(self): ''' Algorithm to check for self intersections in a Bézier curve as explained in 'Calculating the Self-Intersction of Bézier Curves' by Dieter Lasser from Technische Hochschule Darmstadt Department of Mathematics, in West Germany. We're only interested in if there is a self intersection though ''' # Lines connecting initial point, control points and final point of curve # in that order line1 = QLineF(self.initialPoint.position, self.ctrlPoint1.position) line2 = QLineF(self.ctrlPoint1.position, self.ctrlPoint2.position) line3 = QLineF(self.ctrlPoint2.position, self.finalPoint.position) # Angles between the 3 lines angle1 = line1.angleTo( line2) # Positive angle between the first two lines # Fixing the sine for the first angle if line1.angle() < line2.angle(): angle1 *= -1 angle2 = line2.angleTo( line3) # Positive angle between the last two lines # Fixing the sine for the second angle if line2.angle() < line3.angle(): angle2 *= -1 # If the angles sum up to 180 degrees or greater, there is a self-intersection if abs(angle1 + angle2) > 180: return True # Othewise, there is no self intersection return False
def findNearestPoint(self, part_item, target_scenepos): """ Args: part_item (TYPE): Description target_scenepos (TYPE): Description """ li = self._line_item pos = li.mapFromScene(target_scenepos) line = li.line() mouse_point_vec = QLineF(self._CENTER_OF_HELIX, pos) # Check if the click happened on the origin VH if mouse_point_vec.length() < self._RADIUS: # return part_item.mapFromScene(target_scenepos) return None angle_min = 9999 direction_min = None for vector in self.vectors: angle_new = mouse_point_vec.angleTo(vector) if angle_new < angle_min: direction_min = vector angle_min = angle_new if direction_min is not None: li.setLine(direction_min) return part_item.mapFromItem(li, direction_min.p2()) else: print("default point") line.setP2(pos) li.setLine(line) return part_item.mapFromItem(li, pos)
def setActive5p(self, is_active, neighbor_item=None): """Summary Args: is_active (TYPE): Description neighbor_item (None, optional): Description """ phos = self.phos_item bond = self.bond_3p if bond is None: return if not self.is_active5p and is_active: self.pre_xover_item_group.virtual_helix_item.setZValue(styles.ZGRIDHELIX + 10) self.is_active5p = True if neighbor_item is not None: n_scene_pos = neighbor_item.scenePos() p2 = self.mapFromScene(n_scene_pos) bline = bond.line() test = QLineF(bline.p1(), p2) # angle = test.angleTo(bline) + self.theta0 if self.is_fwd else -bline.angleTo(test) + self.theta0 angle = -bline.angleTo(test) + self.theta0 if self.is_fwd else test.angleTo(bline) + self.theta0 else: p2 = self._active_p2_3p angle = -90 if self.is_fwd else 90 self.animate(phos, 'rotation', 300, self.theta0, angle) self.animate(bond, 'bondp2', 300, self._default_p2_3p, p2) elif self.is_active5p: self.pre_xover_item_group.virtual_helix_item.setZValue(styles.ZGRIDHELIX) self.is_active5p = False self.animate(phos, 'rotation', 300, phos.rotation(), self.theta0) self.animate(bond, 'bondp2', 300, bond.line().p2(), self._default_p2_3p)
def setActive5p(self, is_active, neighbor_item=None): """Summary Args: is_active (TYPE): Description neighbor_item (None, optional): Description """ phos = self.phos_item bond = self.bond_3p if bond is None: return if not self.is_active5p and is_active: self.pre_xover_item_group.virtual_helix_item.setZValue(styles.ZSLICEHELIX + 10) self.is_active5p = True if neighbor_item is not None: n_scene_pos = neighbor_item.scenePos() p2 = self.mapFromScene(n_scene_pos) bline = bond.line() test = QLineF(bline.p1(), p2) # angle = test.angleTo(bline) + self.theta0 if self.is_fwd else -bline.angleTo(test) + self.theta0 angle = -bline.angleTo(test) + self.theta0 if self.is_fwd else test.angleTo(bline) + self.theta0 else: p2 = self._active_p2_3p angle = -90 if self.is_fwd else 90 self.animate(phos, 'rotation', 300, self.theta0, angle) self.animate(bond, 'bondp2', 300, self._default_p2_3p, p2) elif self.is_active5p: self.pre_xover_item_group.virtual_helix_item.setZValue(styles.ZSLICEHELIX) self.is_active5p = False self.animate(phos, 'rotation', 300, phos.rotation(), self.theta0) self.animate(bond, 'bondp2', 300, bond.line().p2(), self._default_p2_3p)
def area(self) -> float: d1 = QLineF(self.points[0], self.points[2]) d2 = QLineF(self.points[1], self.points[3]) angle = d1.angleTo(d2) angle = math.radians(angle) d1 = d1.length() d2 = d2.length() return abs(d1 * d2 * math.sin(angle))
def draw(self, painter): rect = QRectF(self.center.x() - self.radius, self.center.y() - self.radius, self.radius * 2, self.radius * 2) lineA = QLineF(self.center, self.A) lineB = QLineF(self.center, self.B) sweepAngle = lineA.angleTo(lineB) if (sweepAngle > 180): sweepAngle -= 360 painter.drawArc(rect, 16 * lineA.angle(), 16 * sweepAngle)