def polygon_orientation(polygon: QgsPolygon): ''' Compute the orientation of a polygon (QgsPolygon) (in degrees) comparatively to the cartographic East (axis X). The orientation is based on the orientation of the associated minimum bounding rectangle. Its value is between 0 and 180 degrees, except if the MBR can not be defined. In that last case, the value -2.0 is returned. ''' # orientedMinimumBoundingBox(self) → Tuple[QgsGeometry, float, float, float, float] # angle (clockwise in degrees from North) (mbr, area, angle, width, height) = polygon.orientedMinimumBoundingBox() if mbr.isNull() or mbr.isEmpty(): return -2.0 # geom = mbr.geometry() v0 = QgsPoint(mbr[0]) v1 = QgsPoint(mbr[1]) v2 = QgsPoint(mbr[2]) length = v0.distanceSquared(v1.x(), v1.y()) length2 = v1.distanceSquared(v2.x(), v2.y()) if length > length2: angle = math.atan2(v0.y() - v1.y(), v0.x() - v1.x()) else: angle = math.atan2(v1.y() - v2.y(), v1.x() - v2.x()) if angle < 0: angle += math.pi return angle * 180.0 / math.pi
def is_rectangle(polygon: QgsPolygon, sd_convex_hull_threshold: float, sd_mbr_threshold: float, distance_area: QgsDistanceArea): ''' Compute if a {@link Polygon} has a rectangular shape or not, based on the comparison with two shapes: the shape of the minimum bounding rectangle of the {@link Polygon}, and the shape of the convex hull associated to the {@link Polygon}. This comparison is computed thanks to two thresholds (threshold of maximums), one for each associated shape. If the shape is rectangular, the orientation (in degrees) based on the is returned; otherwise, the value of -1.0 is returned. Finally, if the returned value equals -2.0, it means that the MBR can not be computed. @param polygon polygon to process @param sd_convex_hull_threshold maximum threshold for surface distance between the polygon and its convex hull @param sd_mbr_threshold maximum threshold for surface distance between the polygon and its associated minimum bounding rectangle @return the orientation in degrees of the polygon, based on the orientation of the associated minimum bounding rectangle, -1.0 if the polygon shape is not defined as a rectangle, and -2.0 if the convex hull or MBR can not be computed ''' convex_hull = polygon.convexHull() if convex_hull.isNull() or convex_hull.isEmpty(): return -2.0 # orientedMinimumBoundingBox(self) → Tuple[QgsGeometry, float, float, float, float] # angle (clockwise in degrees from North) (mbr, area, angle, width, height) = polygon.orientedMinimumBoundingBox() if mbr.isNull() or mbr.isEmpty(): return -2.0 sd_convex_hull = surface_distance(polygon, convex_hull, distance_area) sd_mbr = surface_distance(polygon, mbr, distance_area) if sd_convex_hull <= sd_convex_hull_threshold and sd_mbr <= sd_mbr_threshold: return _mbr_orientation(mbr) return -1.0