def intersectsLine(self, line, path_rect): scene_translation = self.startSocket().sceneTransform() connection_rect = scene_translation.mapRect(self._rect) if connection_rect.contains(path_rect) or path_rect.contains(connection_rect) \ or path_rect.intersects(connection_rect): connection_path = scene_translation.map(self._path) simplified_path = connection_path.simplified() element_count = simplified_path.elementCount() - 1 # In case path is linear if element_count == -1: simplified_path = connection_path element_count = simplified_path.elementCount() previous_point = None for i in range(element_count): element = simplified_path.elementAt(i) point = QPointF(element.x, element.y) if previous_point is not None: segment = QLineF(previous_point, point) intersect_point = QPointF() intersect_type = segment.intersect(line, intersect_point) if intersect_type == QLineF.BoundedIntersection: return True previous_point = point
def pxToDeg(self, x, y): """Transforms pixel coordinates of point to Geographic coordinate system. Args: x, y -- X and Y coordinates of point to process. Returns: QPointF(long, lat) -- longitude and latitude coordinates of given point """ # Please check comments in __stepThree() where we converting step in degrees to pixels in order to understand what we're doing here. # Convert given coordinates to degrees relative to the sides. topX = self.xTL + self.topX * x bottomX = self.xBL + self.bottomX * x # We subtract because Y and lat are not codirectional by default leftY = self.yTL - self.leftY * y rightY = self.yTR - self.rightY * y # Find another coordinate for each side by drawing straight line with calculated coordinate for both points. # Intersection of this line and side will give needed point. # Looks like this: # Y # ^ # | \ <- This is side # | \ # |---*----- <- This line is crossing point relative to the side # | \ # | \ # |------------------> X # Containers for points and result. top, bottom, left, right, res = QPointF(), QPointF(), QPointF( ), QPointF(), QPointF() QLineF.intersect(QLineF(topX, 0, topX, 1), self.top, top) QLineF.intersect(QLineF(bottomX, 0, bottomX, 1), self.bottom, bottom) QLineF.intersect(QLineF(0, leftY, 1, leftY), self.left, left) QLineF.intersect(QLineF(0, rightY, 1, rightY), self.right, right) # We've got coordinates for each side where given point should lie. # Let's draw lines throgh them like this: # ________________________ # | \ | # |_____\__________________| # | \ | # |_______\________________| # Lines are drawn in geographic system, not in pixels. # Their intersection will return given point in geographic system. QLineF.intersect(QLineF(top, bottom), QLineF(left, right), res) return res
def paint(self, painter, option, widget=None): if self.start_item.collidesWithItem(self.end_item): return start_item = self.start_item end_item = self.end_item color = self.color pen = self.pen() pen.setColor(color) arrow_size = 10.0 painter.setPen(pen) painter.setBrush(color) center_line = QLineF(start_item.pos(), end_item.pos()) end_polygon = end_item.polygon p1 = end_polygon.first() + end_item.pos() intersect_point = QPointF() for i in end_polygon: p2 = i + end_item.pos() poly_line = QLineF(p1, p2) intersect_type = poly_line.intersect(center_line, intersect_point) if intersect_type == QLineF.BoundedIntersection: break p1 = p2 self.setLine(QLineF(intersect_point, start_item.pos())) line = self.line() angle = math.acos(line.dx() / max(1, line.length())) if line.dy() >= 0: angle = (math.pi * 2.0) - angle arrow_p1 = (line.p1() + QPointF( math.sin(angle + math.pi / 3.0) * arrow_size, math.cos(angle + math.pi / 3.0) * arrow_size, )) arrow_p2 = (line.p1() + QPointF( math.sin(angle + math.pi - math.pi / 3.0) * arrow_size, math.cos(angle + math.pi - math.pi / 3.0) * arrow_size, )) self.arrow_head.clear() for point in [line.p1(), arrow_p1, arrow_p2]: self.arrow_head.append(point) painter.drawLine(line) painter.drawPolygon(self.arrow_head) if self.isSelected(): painter.setPen(QPen(color, 1, Qt.DashLine)) line = QLineF(line) line.translate(0, 4.0) painter.drawLine(line) line.translate(0, -8.0) painter.drawLine(line)
def paint(self, painter, option, widget=None): if self.myStartItem.collidesWithItem(self.myEndItem): return myStartItem = self.myStartItem myEndItem = self.myEndItem myColor = self.myColor myPen = self.pen() myPen.setColor(self.myColor) arrowSize = 20.0 painter.setPen(myPen) painter.setBrush(self.myColor) centerLine = QLineF(myStartItem.pos(), myEndItem.pos()) endPolygon = myEndItem.polygon() p1 = endPolygon.first() + myEndItem.pos() intersectPoint = QPointF() for i in endPolygon: p2 = i + myEndItem.pos() polyLine = QLineF(p1, p2) intersectType = polyLine.intersect(centerLine, intersectPoint) if intersectType == QLineF.BoundedIntersection: break p1 = p2 self.setLine(QLineF(intersectPoint, myStartItem.pos())) line = self.line() angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = (math.pi * 2.0) - angle arrowP1 = line.p1() + QPointF( math.sin(angle + math.pi / 3.0) * arrowSize, math.cos(angle + math.pi / 3) * arrowSize, ) arrowP2 = line.p1() + QPointF( math.sin(angle + math.pi - math.pi / 3.0) * arrowSize, math.cos(angle + math.pi - math.pi / 3.0) * arrowSize, ) self.arrowHead.clear() for point in [line.p1(), arrowP1, arrowP2]: self.arrowHead.append(point) painter.drawLine(line) painter.drawPolygon(self.arrowHead) if self.isSelected(): painter.setPen(QPen(myColor, 1, Qt.DashLine)) myLine = QLineF(line) myLine.translate(0, 4.0) painter.drawLine(myLine) myLine.translate(0, -8.0) painter.drawLine(myLine)
def paint(self, painter, option, widget=None): if self.my_start_item.collidesWithItem(self.my_end_item): return my_start_item = self.my_start_item my_end_item = self.my_end_item my_color = self.my_color my_pen = self.pen() my_pen.setColor(self.my_color) arrow_size = 20.0 painter.setPen(my_pen) painter.setBrush(my_color) center_line = QLineF(my_start_item.pos(), my_end_item.pos()) end_polygon = my_end_item.polygon p1 = end_polygon.first() + my_end_item.pos() intersect_point = QPointF() for i in end_polygon: p2 = i + my_end_item.pos() poly_line = QLineF(p1, p2) intersect_type = poly_line.intersect(center_line, intersect_point) if intersect_type == QLineF.BoundedIntersection: break p1 = p2 self.setLine(QLineF(intersect_point, my_start_item.pos())) line = self.line() angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = (math.pi * 2) - angle arrow_p1 = line.p1() + QPointF(math.sin(angle + math.pi / 3.0) * arrow_size, math.cos(angle + math.pi / 3) * arrow_size) arrow_p2 = line.p1() + QPointF(math.sin(angle + math.pi - math.pi / 3.0) * arrow_size, math.cos(angle + math.pi - math.pi / 3.0) * arrow_size) self.arrowHead.clear() for point in [line.p1(), arrow_p1, arrow_p2]: self.arrowHead.append(point) painter.drawLine(line) painter.drawPolygon(self.arrowHead) if self.isSelected(): painter.setPen(QPen(my_color, 1, Qt.DashLine)) my_line = QLineF(line) my_line.translate(0, 4.0) painter.drawLine(my_line) my_line.translate(0, -8.0) painter.drawLine(my_line)
def intersectLineGeometry(self, lineGeo, breakShape): """ Try to break lineGeo with the given breakShape. Will return the intersection points of lineGeo with breakShape. """ # TODO geos should be abs intersections = [] line = QLineF(lineGeo.Ps.x, lineGeo.Ps.y, lineGeo.Pe.x, lineGeo.Pe.y) for breakGeo in breakShape.geos.abs_iter(): if isinstance(breakGeo, LineGeo): breakLine = QLineF(breakGeo.Ps.x, breakGeo.Ps.y, breakGeo.Pe.x, breakGeo.Pe.y) intersection = QPointF(0, 0) # values do not matter res = line.intersect(breakLine, intersection) if res == QLineF.BoundedIntersection: intersections.append(Point(intersection.x(), intersection.y())) return intersections
def intersection(self, line): """ Returns the intersection of the shape with the given line (in scene coordinates). :type line: QLineF :rtype: QPointF """ intersection = QPointF() path = self.painterPath() polygon = self.mapToScene(path.toFillPolygon(self.transform())) for i in range(0, polygon.size() - 1): polyline = QLineF(polygon[i], polygon[i + 1]) if polyline.intersect(line, intersection) == QLineF.BoundedIntersection: return intersection return None
def __findRectIntersectionPoint(self, item, p1, p2): """ Private method to find the intersetion point of a line with a rectangle. @param item item to check against @param p1 first point of the line (QPointF) @param p2 second point of the line (QPointF) @return the intersection point (QPointF) """ rect = self.__mapRectFromItem(item) lines = [ QLineF(rect.topLeft(), rect.topRight()), QLineF(rect.topLeft(), rect.bottomLeft()), QLineF(rect.bottomRight(), rect.bottomLeft()), QLineF(rect.bottomRight(), rect.topRight()), ] intersectLine = QLineF(p1, p2) intersectPoint = QPointF(0, 0) for line in lines: if intersectLine.intersect(line, intersectPoint) == QLineF.BoundedIntersection: return intersectPoint return QPointF(-1.0, -1.0)
def __findRectIntersectionPoint(self, item, p1, p2): """ Private method to find the intersetion point of a line with a rectangle. @param item item to check against @param p1 first point of the line (QPointF) @param p2 second point of the line (QPointF) @return the intersection point (QPointF) """ rect = self.__mapRectFromItem(item) lines = [ QLineF(rect.topLeft(), rect.topRight()), QLineF(rect.topLeft(), rect.bottomLeft()), QLineF(rect.bottomRight(), rect.bottomLeft()), QLineF(rect.bottomRight(), rect.topRight()) ] intersectLine = QLineF(p1, p2) intersectPoint = QPointF(0, 0) for line in lines: if intersectLine.intersect(line, intersectPoint) == \ QLineF.BoundedIntersection: return intersectPoint return QPointF(-1.0, -1.0)
def __stepThree(self): """Step 3 -- Do basically everything. """ # Validate data def setError(e): """Displays string e. """ self.lblDataError.setText("<html><head/><body><div>" + self.lang.errData + e + "</div></body></html>") # Try to read data. We need to create fields, because this will be used later in other functions. self.xTL = self.__sfloat(self.xTopLeft.text()) self.xTR = self.__sfloat(self.xTopRight.text()) self.xBL = self.__sfloat(self.xBottomLeft.text()) self.xBR = self.__sfloat(self.xBottomRight.text()) self.yTL = self.__sfloat(self.yTopLeft.text()) self.yTR = self.__sfloat(self.yTopRight.text()) self.yBL = self.__sfloat(self.yBottomLeft.text()) self.yBR = self.__sfloat(self.yBottomRight.text()) self.xD = self.__sfloat(self.xDelimiter.text()) self.yD = self.__sfloat(self.yDelimiter.text()) # Convert delimiters to pixels. # Value of another coordinate doesn't matter. # If you'll draw a random line and draw crossing lines parallel to one of axes with same distance between these lines by another axis, you'll split your random line into equal pieces. # See for yourself: # Y # ^ ___\_____ # | ____\____ # | _____\___ # | \ # |-----------> X # You can try it on paper or prove this "theorem" doing some math. try: self.xDTop = self.width / abs(self.xTL - self.xTR) * self.xD self.xDBottom = self.width / abs(self.xBL - self.xBR) * self.xD self.yDLeft = self.height / abs(self.yTL - self.yBL) * self.yD self.yDRight = self.height / abs(self.yTR - self.yBR) * self.yD except ZeroDivisionError: setError(self.lang.errCorners) return # Now do the same stuff, but find how much pixels in one degree. # We won't find absolute value for subtraction because axes of image in geographic system may be not codirectional to axes of image in Qt system. self.topX = (self.xTR - self.xTL) / self.width self.bottomX = (self.xBR - self.xBL) / self.width self.leftY = (self.yTL - self.yBL) / self.height self.rightY = (self.yTR - self.yBR) / self.height # Sides of image in geographic system self.top = QLineF(self.xTL, self.yTL, self.xTR, self.yTR) self.bottom = QLineF(self.xBL, self.yBL, self.xBR, self.yBR) self.left = QLineF(self.xTL, self.yTL, self.xBL, self.yBL) self.right = QLineF(self.xTR, self.yTR, self.xBR, self.yBR) errors = "" if self.xDTop > self.width: errors += self.lang.errLongTop + "<br>" if self.xDBottom > self.width: errors += self.lang.errLongBottom + "<br>" if self.yDLeft > self.height: errors += self.lang.errLatLeft + "<br>" if self.yDRight > self.height: errors += self.lang.errLatRight + "<br>" if errors != "": setError(self.lang.errSides + "<br>" + errors) return # Check if given coordinates form 8-shaped figure if (self.xTL > self.xTR and self.xBL < self.xBR) or ( self.xTL < self.xTR and self.xBL > self.xBR) or ( self.yTL > self.yBL and self.yTR < self.yBR) or (self.yTL < self.yBL and self.yTR > self.yTL): choice = QMessageBox(QMessageBox.Warning, "AerialWare", self.lang.warningCoordinates, QMessageBox.Yes | QMessageBox.No).exec() if choice == QMessageBox.No: return # Draw grid # Set points for grid # Points will look like: # [point, point, ...], # [point, point, ...], ... pointRows = [] # Let x1, y1; x2, y2 be vertical line # and x3, y3; x4, y4 be horizontal line. # Thus, y1 and y2 should be always on top and bottom; # x3, x4 -- on left and right y1, y2, x3, x4 = 0, self.height, 0, self.width # So we have to change: # for vertical line: x1, x2 # for horizontal line: y3, y4 y3 = y4 = 0 # Initial values for horizontal line # Move horizontal line while y3 <= self.height + self.yDLeft / 2 or y4 <= self.height + self.yDRight / 2: x1 = x2 = 0 # Initial values for vertical line # Move vertical line points = [] while x1 <= self.width + self.xDTop / 2 or x2 <= self.width + self.xDBottom / 2: point = QPointF() QLineF.intersect(QLineF(x1, y1, x2, y2), QLineF(x3, y3, x4, y4), point) points.append(point) x1 += self.xDTop x2 += self.xDBottom if points != []: pointRows.append(points) y3 += self.yDLeft y4 += self.yDRight # If nothing has been added if points == []: setError(self.lang.errPoints) return # Get scene geometry to preserve scene expanding rect = self.scene.sceneRect() # And add bounds for the grid self.bounds = QGraphicsRectItem(rect) self.bounds.setFlag(self.bounds.ItemClipsChildrenToShape) self.scene.addItem(self.bounds) # Create polygons from points # We'll recheck previous item i = 1 # Rows while i < len(pointRows): j = 1 # Points while j < len(pointRows[i]): # Add points in following order: top left, top right, bottom right, bottom left points = [ pointRows[i - 1][j - 1], pointRows[i - 1][j], pointRows[i][j], pointRows[i][j - 1] ] # We're assigning self.bounds as parent implicitly, so we shouldn't add polygon to scene by ourselves. poly = _QCustomGraphicsPolygonItem(QPolygonF(points), self.bounds) poly.setRowCol(i - 1, j - 1) j += 1 i += 1 # Restore scene geometry self.scene.setSceneRect(rect) self.__turnPage() self.btnNext.disconnect() self.btnNext.clicked.connect(self.__stepFour)
def paint(self, painter, options, widget=None): """ Painter implementation for the arrow. First it draws the line and then the triangle on the end :param painter: The painter, which draws the node :param options: options for the paint job :param widget: widget of the Item """ if self.start.collidesWithItem(self.dst): return myPen = self.pen() arrowSize = 10 painter.setPen(myPen) painter.setBrush(myPen.color()) """ Calculation for the line """ centerLine = QLineF(QPointF(self.start.x() + self.start.boundingRect().center().x() + self.offset, self.start.y() + self.start.boundingRect().bottom()), QPointF(self.dst.x() + self.dst.boundingRect().center().x(), self.dst.y())) endPolygon = self.dst.mapFromItem(self.dst, self.dst.boundingRect()) p1 = endPolygon.first() + self.dst.pos() p2 = None intersectPoint = QPointF() for i in endPolygon: p2 = i + self.dst.pos() polyLine = QLineF(p1, p2) intersectType = polyLine.intersect(centerLine, intersectPoint) if intersectType == QLineF.BoundedIntersection: break p1 = p2 self.setLine(QLineF(intersectPoint, QPointF(self.start.x() + self.start.boundingRect().center().x() + self.offset, self.start.y() + self.start.boundingRect().bottom()))) """ Calculation for the arrow It calculates an left and an right part of the arrow """ angle = math.atan2(-self.line().dy(), self.line().dx()) arrowP1 = self.line().p1() + QPointF(math.sin(angle + math.pi / 3) * arrowSize, math.cos(angle + math.pi / 3) * arrowSize) arrowP2 = self.line().p1() + QPointF(math.sin(angle + math.pi - math.pi / 3) * arrowSize, math.cos(angle + math.pi - math.pi / 3) * arrowSize) self.arrowHead.clear() self.arrowHead << self.line().p1() << arrowP1 << arrowP2 painter.drawLine(self.line()) painter.drawPolygon(self.arrowHead) if self.isSelected(): painter.setPen(QPen(Qt.black, 1, Qt.DashLine)) myLine = self.line() myLine.translate(0, 4.0) painter.drawLine(myLine) myLine.translate(0, -8.0) painter.drawLine(myLine)