class CADTriangle(object): def __init__(self, p1, p2, p3): if not all(isinstance(p, (CADPoint, QgsPoint)) for p in [p1, p2, p3]): raise AttributeError else: self.__points = [CADPoint(p1), CADPoint(p2), CADPoint(p3)] self.__update() def __update(self): self.__A = self.__points[0] self.__B = self.__points[1] self.__C = self.__points[2] self.__updateAngles() self.__updateSides() self.__updateLengths() self.__updateCenter() self.__updateArea() def __updateAngles(self): self.__angles = [] for i in range(0, 3): self.__angles.append( self.__points[i % 3].getAngleOfLineBetweenTwoPoints( self.__points[(i + 1) % 3])) def __updateSides(self): self.__sides = [ CADLine(self.__A, self.__B), CADLine(self.__B, self.__C), CADLine(self.__C, self.__A) ] def __updateLengths(self): # A = points[0] # B = points[1] # C = points[2] # a (lengths[0]) = [BC] # b (lengths[1]) = [AC] # c (lengths[2]) = [AB] self.__a = self.__B.distance(self.__C) self.__b = self.__A.distance(self.__C) self.__c = self.__A.distance(self.__B) self.__lengths = [self.__a, self.__b, self.__c] self.__updatePerimeter() def __updatePerimeter(self): self._perimeter = reduce(operator.add, self.__lengths) def __updateArea(self): # area = abs((Ax(By-Cy)+Bx(Cy-Ay)+Cx(Ay-By))/2) Ax = self.__A.x Ay = self.__A.y Bx = self.__B.x By = self.__B.y Cx = self.__C.x Cy = self.__C.y self._area = math.fabs( (Ax * (By - Cy) + Bx * (Cy - Ay) + Cx * (Ay - By)) / 2) def __updateCenter(self): self.__center = QgsPoint() self.__center.setX((self.__A.x + self.__B.x + self.__C.x) / 3) self.__center.setY((self.__A.x + self.__B.x + self.__C.x) / 3) @property def area(self): return self._area @property def perimeter(self): return self._perimeter @property # Adapted from SymPy def altitudes(self): """The altitudes of the triangle. An altitude of a triangle is a segment through a vertex, perpendicular to the opposite side, with length being the height of the vertex measured from the line containing the side. """ s = self.__sides v = self.__points return { v[0]: s[1].perpendicular_segment(v[0]), v[1]: s[2].perpendicular_segment(v[1]), v[2]: s[0].perpendicular_segment(v[2]) } @property # Adapted from SymPy def orthocenter(self): """The orthocenter of the triangle. The orthocenter is the intersection of the altitudes of a triangle. It may lie inside, outside or on the triangle. """ a = self.altitudes v = self.__points l1 = a[v[0]] l2 = a[v[1]] return CADLine(l1.p1, l1.p2).intersection(CADLine(l2.p1, l2.p2)) # Adapted from SymPy def bisectors(self): """The angle bisectors of the triangle. An angle bisector of a triangle is a straight line through a vertex which cuts the corresponding angle in half. """ s = self.__sides v = self.__points c = self.incenter l1 = Segment(v[0], Line(v[0], c).intersection(s[1])[0]) l2 = Segment(v[1], Line(v[1], c).intersection(s[2])[0]) l3 = Segment(v[2], Line(v[2], c).intersection(s[0])[0]) return {v[0]: l1, v[1]: l2, v[2]: l3} @property # Adapted from SymPy def medians(self): """The medians of the triangle. A median of a triangle is a straight line through a vertex and the midpoint of the opposite side, and divides the triangle into two equal areas. """ s = self.__sides v = self.__points return { v[0]: Segment(v[0], s[1].midpoint), v[1]: Segment(v[1], s[2].midpoint), v[2]: Segment(v[2], s[0].midpoint) } @property # Adapted from SymPy def medial(self): """The medial triangle of the triangle. The triangle which is formed from the midpoints of the three sides. """ s = self.__sides return CADTriangle(s[0].midpoint, s[1].midpoint, s[2].midpoint) @property def circumcenter(self): Ax = self.__A.x Ay = self.__A.x Bx = self.__B.x By = self.__B.x Cx = self.__C.x Cy = self.__C.x D = 2 * (Ax * (By - Cy) + Bx * (Cy - Ay) + Cx * (Ay - By)) x = ((Ax * Ax + Ay * Ay) * (By - Cy) + (Bx * Bx + By * By) * (Cy - Ay) + (Cx * Cx + Cy * Cy) * (Ay - By)) / D y = ((Ax * Ax + Ay * Ay) * (Cx - Bx) + (Bx * Bx + By * By) * (Ax - Cx) + (Cx * Cx + Cy * Cy) * (Bx - Ax)) / D return CADPoint(x, y) @property def circumradius(self): radius = (reduce(operator.mul, self.__lengths) / math.sqrt( (self.__a + self.__b + self.__c) * (self.__b + self.__c - self.__a) * (self.__c + self.__a - self.__b) * (self.__a + self.__b - self.__c))) return radius @property # Adapted from SymPy def cicumscribedCircle(self): return CADCircle(self.circumcenter, self.circumradius) @property # Adapted from SymPy def incenter(self): x = (self.__a * self.__A.x + self.__b * self.__B.x + self.__c * self.__C.x) / self._perimeter y = (self.__a * self.__A.x + self.__b * self.__B.x + self.__c * self.__C.x) / self._perimeter return CADPoint(x, y) @property # Adapted from SymPy def inradius(self): return (2 * self._area) / self._perimeter @property # Adapted from SymPy def inscribedCircle(self): return CADCircle(self.incenter, self.inradius) def isIsocele(self, lengthTolerance=0.0001): """Are two or more of the sides the same length? """ l0l1 = near(self.__lengths[0], self.__lengths[1], lengthTolerance) l1l2 = near(self.__lengths[1], self.__lengths[2], lengthTolerance) l2l0 = near(self.__lengths[2], self.__lengths[0], lengthTolerance) if l0l1 is True or l1l2 is True or l2l0 is True: return True return False def isEquilateral(self, lengthTolerance=0.0001, angleTolerance=0.001): """Are all the sides the same length? """ l0l1 = near(self.__lengths[0], self.__lengths[1], lengthTolerance) l1l2 = near(self.__lengths[1], self.__lengths[2], lengthTolerance) l2l0 = near(self.__lengths[2], self.__lengths[0], lengthTolerance) if l0l1 is True and l1l2 is True and l2l0 is True: l0l1 = near(self.__angles[0], self.__angles[1], angleTolerance) l1l2 = near(self.__angles[1], self.__angles[2], angleTolerance) l2l0 = near(self.__angles[2], self.__angles[0], angleTolerance) if a0a1 is True and a1a2 is True and a2a0 is True: return True return False def isRight(self, angleTolerance=0.001): """Is the triangle right-angled. """ for i in range(0, 3): if near(self.__angles[i], 90.0, angleTolerance): return True return False # Adapted from SymPy def isScalene(self): """Are all the sides of the triangle of different lengths? """ return len(set(self.__lengths)) == 3 @classmethod def fromQgsGeometry(cls, geom): tri = None if not isinstance(geom, QgsGeometry): raise AttributeError try: if geom.type() == QGis.Polygon: g = geom.toPolygon() if len(g) != 4 and isCollinear(g[0], g[1], g[2]) == 0: raise ValueError else: tri = g[:3] elif geom.type() == QGis.Polyline: g = geom.toPolyline() if len(g) != 3 and isCollinear(g[0], g[1], g[2]) == 0: raise ValueError else: tri = g[:] except: raise ValueError if tri: return cls(tri[0], tri[1], tri[2]) return None @classmethod def fromCADRegularPolygon(self, rp): if not isinstance(rp, CADRegularPolygon) or rp.nbEdges != 3: raise AttributeError try: points = [p for p in rp] if len(points) != 3: raise ValueError else: return cls(points[0], points[1], points[2]) except: raise ValueError return None def exportToQgsGeometry(self): return QgsGeometry.fromPolygon([self.__points]) def exportToCADRegularPolygon(self): if self.isEquilateral(): return CADRegularPolygon(self.__center, self.__points[0]) else: raise ValueError
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_VECTOR)) rasterPath = unicode(self.getParameterValue(self.INPUT_RASTER)) rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly) geoTransform = rasterDS.GetGeoTransform() rasterDS = None fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('poly_id', QVariant.Int, '', 10, 0)) fields.append(QgsField('point_id', QVariant.Int, '', 10, 0)) writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter( fields.toList(), QGis.WKBPoint, layer.crs()) outFeature = QgsFeature() outFeature.setFields(fields) point = QgsPoint() fid = 0 polyId = 0 pointId = 0 current = 0 features = vector.features(layer) total = 100.0 / len(features) for f in features: geom = f.geometry() bbox = geom.boundingBox() xMin = bbox.xMinimum() xMax = bbox.xMaximum() yMin = bbox.yMinimum() yMax = bbox.yMaximum() (startRow, startColumn) = raster.mapToPixel(xMin, yMax, geoTransform) (endRow, endColumn) = raster.mapToPixel(xMax, yMin, geoTransform) for row in xrange(startRow, endRow + 1): for col in xrange(startColumn, endColumn + 1): (x, y) = raster.pixelToMap(row, col, geoTransform) point.setX(x) point.setY(y) if geom.contains(point): outFeature.setGeometry(QgsGeometry.fromPoint(point)) outFeature['id'] = fid outFeature['poly_id'] = polyId outFeature['point_id'] = pointId fid += 1 pointId += 1 writer.addFeature(outFeature) pointId = 0 polyId += 1 current += 1 progress.setPercentage(int(current * total)) del writer
class CoordinatesWidget(QWidget): """ Custom widget for entering an X,Y coordinate pair. """ def __init__(self, parent=None, x=0, y=0): QWidget.__init__(self, parent) self.resize(270, 130) self._gridLayout = QGridLayout(self) self._sbYCoord = QDoubleSpinBox(self) self._sbYCoord.setMinimumSize(QSize(0, 30)) self._sbYCoord.setDecimals(5) self._sbYCoord.setMinimum(-180.0) self._sbYCoord.setMaximum(180.0) self._gridLayout.addWidget(self._sbYCoord, 2, 1, 1, 1) self._label_2 = QLabel(self) self._label_2.setText( QApplication.translate("CoordinatesWidget", "Y-Coordinate")) self._gridLayout.addWidget(self._label_2, 2, 0, 1, 1) self._label = QLabel(self) self._label.setMaximumSize(QSize(80, 16777215)) self._label.setText( QApplication.translate("CoordinatesWidget", "X-Coordinate")) self._gridLayout.addWidget(self._label, 1, 0, 1, 1) self._sbXCoord = QDoubleSpinBox(self) self._sbXCoord.setMinimumSize(QSize(0, 30)) self._sbXCoord.setDecimals(5) self._sbXCoord.setMinimum(-180.0) self._sbXCoord.setMaximum(180.0) self._gridLayout.addWidget(self._sbXCoord, 1, 1, 1, 1) self.vlNotification = QVBoxLayout() self._gridLayout.addLayout(self.vlNotification, 0, 0, 1, 2) # Set X and Y values self._sbXCoord.setValue(float(x)) self._sbYCoord.setValue(float(y)) self._geomPoint = QgsPoint(x, y) # Use default SRID self._srid = 4326 # Connect signals self._sbXCoord.valueChanged.connect(self.onXCoordValueChanged) self._sbYCoord.valueChanged.connect(self.onYCoordValueChanged) def onXCoordValueChanged(self, value): """ Slot raised when the value of the X-Coordinate spinbox changes """ self._geomPoint.setX(value) def onYCoordValueChanged(self, value): """ Slot raised when the value of the Y-Coordinate spinbox changes """ self._geomPoint.setY(value) def xCoord(self): return self._geomPoint.x() def yCoord(self): return self._geomPoint.y() def XY(self): return (self.xCoord(), self.yCoord()) def setX(self, xCoord): self._sbXCoord.setValue(xCoord) def setY(self, yCoord): self._sbYCoord.setValue(yCoord) def setXY(self, x, y): """ Set both X and Y coordinate values. """ self.setX(x) self.setY(y) def geomPoint(self): """ Returns the coordinate representation as a QgsPoint. """ return self._geomPoint def clear(self): """ Clears the value from x and y coordinate spinbox. """ self._sbXCoord.clear() self._sbYCoord.clear() def setSRID(self, geoModel): """ Set the SRID using the SRID by using that one specified in the geometry column of an sqlalchemy object. """ if hasattr(geoModel, "SRID"): self._srid = geoModel.SRID() def toEWKT(self): """ Returns the specified X,Y point as an extended well-known text representation. PostGIS 2.0 requires geometry to be in EWKT specification. """ return "SRID={0};{1}".format(str(self._srid), self._geomPoint.wellKnownText())
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_VECTOR)) rasterPath = unicode(self.getParameterValue(self.INPUT_RASTER)) rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly) geoTransform = rasterDS.GetGeoTransform() rasterDS = None fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('poly_id', QVariant.Int, '', 10, 0)) fields.append(QgsField('point_id', QVariant.Int, '', 10, 0)) writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter( fields.toList(), QGis.WKBPoint, layer.crs()) outFeature = QgsFeature() outFeature.setFields(fields) point = QgsPoint() fid = 0 polyId = 0 pointId = 0 current = 0 features = vector.features(layer) total = 100.0 / len(features) for f in features: geom = f.geometry() bbox = geom.boundingBox() xMin = bbox.xMinimum() xMax = bbox.xMaximum() yMin = bbox.yMinimum() yMax = bbox.yMaximum() (startRow, startColumn) = raster.mapToPixel(xMin, yMax, geoTransform) (endRow, endColumn) = raster.mapToPixel(xMax, yMin, geoTransform) for row in xrange(startRow, endRow + 1): for col in xrange(startColumn, endColumn + 1): (x, y) = raster.pixelToMap(row, col, geoTransform) point.setX(x) point.setY(y) if geom.contains(point): outFeature.setGeometry(QgsGeometry.fromPoint(point)) outFeature['id'] = fid outFeature['poly_id'] = polyId outFeature['point_id'] = pointId fid += 1 pointId += 1 writer.addFeature(outFeature) pointId = 0 polyId += 1 current += 1 progress.setPercentage(int(current * total)) del writer
class CoordinatesWidget(QWidget): """ Custom widget for entering an X,Y coordinate pair. """ def __init__(self,parent = None,x=0,y=0): QWidget.__init__(self,parent) self.resize(270, 130) self._gridLayout = QGridLayout(self) self._sbYCoord = QDoubleSpinBox(self) self._sbYCoord.setMinimumSize(QSize(0, 30)) self._sbYCoord.setDecimals(5) self._sbYCoord.setMinimum(-180.0) self._sbYCoord.setMaximum(180.0) self._gridLayout.addWidget(self._sbYCoord, 2, 1, 1, 1) self._label_2 = QLabel(self) self._label_2.setText(QApplication.translate("CoordinatesWidget","Y-Coordinate")) self._gridLayout.addWidget(self._label_2, 2, 0, 1, 1) self._label = QLabel(self) self._label.setMaximumSize(QSize(80, 16777215)) self._label.setText(QApplication.translate("CoordinatesWidget","X-Coordinate")) self._gridLayout.addWidget(self._label, 1, 0, 1, 1) self._sbXCoord = QDoubleSpinBox(self) self._sbXCoord.setMinimumSize(QSize(0, 30)) self._sbXCoord.setDecimals(5) self._sbXCoord.setMinimum(-180.0) self._sbXCoord.setMaximum(180.0) self._gridLayout.addWidget(self._sbXCoord, 1, 1, 1, 1) self.vlNotification = QVBoxLayout() self._gridLayout.addLayout(self.vlNotification, 0, 0, 1, 2) #Set X and Y values self._sbXCoord.setValue(float(x)) self._sbYCoord.setValue(float(y)) self._geomPoint = QgsPoint(x,y) #Use default SRID self._srid = 4326 #Connect signals self._sbXCoord.valueChanged.connect(self.onXCoordValueChanged) self._sbYCoord.valueChanged.connect(self.onYCoordValueChanged) def onXCoordValueChanged(self,value): """ Slot raised when the value of the X-Coordinate spinbox changes """ self._geomPoint.setX(value) def onYCoordValueChanged(self,value): """ Slot raised when the value of the Y-Coordinate spinbox changes """ self._geomPoint.setY(value) def xCoord(self): return self._geomPoint.x() def yCoord(self): return self._geomPoint.y() def XY(self): return (self.xCoord(),self.yCoord()) def setX(self,xCoord): self._sbXCoord.setValue(xCoord) def setY(self,yCoord): self._sbYCoord.setValue(yCoord) def setXY(self,x,y): """ Set both X and Y coordinate values. """ self.setX(x) self.setY(y) def geomPoint(self): """ Returns the coordinate representation as a QgsPoint. """ return self._geomPoint def setSRID(self,geoModel): """ Set the SRID using the SRID by using that one specified in the geometry column of an sqlalchemy object. """ if hasattr(geoModel,"SRID"): self._srid = geoModel.SRID() def toEWKT(self): """ Returns the specified X,Y point as an extended well-known text representation. PostGIS 2.0 requires geometry to be in EWKT specification. """ return "SRID={0};{1}".format(str(self._srid),self._geomPoint.wellKnownText())