Exemplo n.º 1
0
    def by3Points(cls, p1, p2, p3):
        """Create a CADRectangle with 2 points (AD) and a length (X - AD)
        D-------C
        |       X
        A-------B
        """
        if not isinstance(p1, (CADPoint, QgsPoint)) or \
           not isinstance(p2, (CADPoint, QgsPoint)) or \
           not isinstance(p3, (CADPoint, QgsPoint)):
            raise AttributeError

        p1 = CADPoint(p1)
        p2 = CADPoint(p2)
        p3 = CADPoint(p3)

        l = CADLine(p1, p2)
        angle_exist = p1.getAngleOfLineBetweenTwoPoints(p2)
        side = CADPoint.isCollinear(p1, p2, p3)
        if side == 0:
            return None

        pp = CADLine.pointOnALine(CADLine(p1, p2), p3)

        length = p3.distance(pp) * side

        p3 = p2.pointProjected(length, 90 + angle_exist)
        p4 = p1.pointProjected(length, 90 + angle_exist)

        return cls(p1, p2, p3, p4)
Exemplo n.º 2
0
    def by2PointsAndWidth(cls, p1, p2, w):
        """Create a CADRectangle with 2 points (AD) and the width
        D-------C
        |       |
        A-------B
        """

        if not isinstance(p1, (CADPoint, QgsPoint)) or \
           not isinstance(p2, (CADPoint, QgsPoint)) or \
           not isinstance(w, (float, long, int)):
            raise AttributeError

        p1 = CADPoint(p1)
        p2 = CADPoint(p2)

        angle_exist = p1.getAngleOfLineBetweenTwoPoints(p2)

        pt1 = p1
        pt2 = p1.pointProjected(w, 90 - angle_exist)
        pt3 = p2.pointProjected(w, 90 - angle_exist)
        pt4 = p2

        l = CADLine(p1, p2)
        if CADPoint.isCollinear(pt1, pt2, pt3) == 0:
            pt2 = p1.pointProjected(w, 90 + angle_exist)
            pt3 = p2.pointProjected(w, 90 + angle_exist)

        return cls(pt1, pt2, pt3, pt4)
Exemplo n.º 3
0
    def byCenter2Points(cls, pc, p1, p2):
        """Create an ellipse by center and 2 points for axis.

             /----p2----\
            /            \
            |     pc     p1
            \            /
             \----------/
        """
        if not isinstance(pc, (QgsPoint, CADPoint)) \
            or not isinstance(p1,
                              (QgsPoint, CADPoint)) \
            or not isinstance(p2,
                              (QgsPoint, CADPoint)):
            raise AttributeError

        pc = CADPoint(pc)
        p1 = CADPoint(p1)
        p2 = CADPoint(p2)

        angle_exist = pc.getAngleOfLineBetweenTwoPoints(p1)

        axis_a = pc.distance(p1)

        pp = CADLine.pointOnALine(CADLine(pc, p1), p2)
        length = p2.distance(pp)
        pp2 = pc.pointProjected(length, 90 + angle_exist)
        axis_b = pc.distance(pp2)

        return cls(pc, axis_a, axis_b, angle_exist)
Exemplo n.º 4
0
    def by2Corners(cls, p1, p2, nbEdges=5):
        """CADRegularPolygon by 2 corners (AB):
           A----B
          /      \
         /        \
         \        /
          \------/
          """
        if not isinstance(p1, (QgsPoint, CADPoint)) or \
           not isinstance(p2, (QgsPoint, CADPoint)) or \
           not isinstance(nbEdges, (long, int)):
            raise AttributeError
        else:
            p1 = CADPoint(p1)
            p2 = CADPoint(p2)
            angle_exist = p1.getAngleOfLineBetweenTwoPoints(p2)
            pm = p1.midpoint(p2)
            length = p1.distance(pm)

            angle = (180.0 - (360.0 / nbEdges)) / 2.0
            hypo = length / math.cos(math.radians(angle))
            pc = p1.pointProjected(hypo, angle_exist + angle)

            return cls(pc, p1, nbEdges)

        return None
Exemplo n.º 5
0
    def byPointHeightWidthAndAngle(cls, p1, h, w, a):
        """Create a CADRectangle with base point (A) and the height, width and an angle
        D-------C
        |       |
        A-------B
        """
        if not isinstance(p1, (CADPoint, QgsPoint)) \
            or not isinstance(h,
                              (float, long, int)) \
            or not isinstance(w,
                              (float, long, int)) \
            or not isinstance(a,
                              (float, long, int)):
            raise AttributeError

        p1 = CADPoint(p1)

        p2 = p1.pointProjected(w, a)
        p3 = p2.pointProjected(h, 90 + a)
        p4 = p1.pointProjected(h, 90 + a)

        return cls(p1, p2, p3, p4)
Exemplo n.º 6
0
    def byCenterPointAngle(cls, ptCenter, ptStart, inAngle, direction=1):
        """Create a CADCirclurArc with by Center C a point A and angle
         A   C
         |
          \------/Angle
        """
        if not all([isinstance(p, (CADPoint, QgsPoint))
                    for p in [ptCenter, ptStart]]) or \
           not isinstance(inAngle, (int, long, float)) or \
           not isinstance(direction, (int, long)):
            raise AttributeError

        ptCenter = CADPoint(ptCenter)
        ptStart = CADPoint(ptStart)
        angle = ptCenter.getAngleOfLineBetweenTwoPoints(ptStart)
        dist = ptCenter.distance(ptStart)

        if inAngle < 0:
            inAngle += 360
        ptAngle = 0
        if direction == 1:
            ptAngle = angle - (360 - inAngle)
        elif direction == -1:
            ptAngle = angle + inAngle

        ptEnd = ptCenter.pointProjected(dist, ptAngle)
        ptAngle_arc = ptCenter.getAngleOfLineBetweenTwoPoints(
            ptStart.midpoint(ptEnd))
        if direction == 1:
            if inAngle < 180:
                ptAngle_arc = ptAngle_arc + 180
        if direction == -1:
            if inAngle > 180:
                ptAngle_arc = ptAngle_arc - 180
        ptArc = ptCenter.pointProjected(dist, ptAngle_arc)

        return cls(ptStart, ptEnd, ptArc)
Exemplo n.º 7
0
    def rotate(self, pr, a):
        """Rotate a CADRectangle with angle `a` and base point `pr`
        D-------C
        |       |
        A-------B
        """
        if not isinstance(pr, (CADPoint, QgsPoint)) \
            or not isinstance(a,
                              (float, long, int)):
            pass
        else:
            pr = CADPoint(pr)

            dist = [pr.distance(i) for i in self.__points]
            angle_exist = [
                pr.getAngleOfLineBetweenTwoPoints(p) for p in self.__points
            ]
            for i, p in enumerate(self.__points):
                self.__points[i] = pr.pointProjected(dist[i],
                                                     angle_exist[i] + a)
            self.__update()
Exemplo n.º 8
0
class CADCircle(object):
    def __init__(self, pc, radius):
        if not isinstance(pc, (CADPoint, QgsPoint)) or \
           not isinstance(radius, (float, long, int)):
            raise AttributeError
        else:
            self._center = CADPoint(pc)
            self._radius = radius

    def __iter__(self, segments=36):
        for t in [(2 * math.pi) / segments * i for i in range(segments)]:
            yield self._center.pointProjected(self._radius, math.degrees(t))

    def __repr__(self):
        return "CADCircle({}, {})".format(self.center, self.radius)

    def __str__(self):
        s = "Circle:\n"
        s += "Center: %s\nRadius: %.3f\n" % (self.center, self.radius)
        s += "Area: %.3f\nPerimeter: %.3f\n" % (self.area, self.perimeter)

        return s

    def quadrant(self):
        """Return 4 coordinates [East, North, West, South]
        of circle's quadrant"""
        N = CADPoint(self._center.x, self._center.y + self._radius)
        S = CADPoint(self._center.x, self._center.y - self._radius)
        E = CADPoint(self._center.x + self._radius, self._center.y)
        W = CADPoint(self._center.x - self._radius, self._center.y)
        return [E, N, W, S]

    @property
    def center(self):
        return self._center

    @center.setter
    def center(self, pc):
        if not isinstance(pc, (CADPoint, QgsPoint)):
            raise AttributeError
        else:
            self._center = CADPoint(pc)

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, r):
        if not isinstance(radius, (float, long, int)):
            raise AttributeError
        else:
            self._radius = r

    @property
    def area(self):
        return math.pi * self.radius * self.radius

    @property
    def perimeter(self):
        return 2 * math.pi * self.radius

    @classmethod
    def by2Points(cls, p1, p2):
        """Create a CADCircle with 2 points (from diameter : AB)
          /------\
         |        |
         A        B
         |        |
          \------/
        """
        if not all(isinstance(p, (QgsPoint, CADPoint)) for p in [p1, p2]):
            raise AttributeError

        p1 = CADPoint(p1)
        p2 = CADPoint(p2)

        center = p1.midpoint(p2)
        radius = p1.distance(center)

        return cls(center, radius)

    @classmethod
    def by3Points(cls, p1, p2, p3, epsilon=1e-8):
        """Create a CADCircle with 3 points ABC
          /------\
         |        |
         A        C
         |        |
          \--B---/
        """
        if not all(isinstance(p, (QgsPoint, CADPoint)) for p in [p1, p2, p3]):
            raise AttributeError

        p1 = CADPoint(p1)
        p2 = CADPoint(p2)
        p3 = CADPoint(p3)

        # Paul Bourke's algorithm
        m_Center = CADPoint()
        m_dRadius = -1
        yDelta_a = p2.y - p1.y
        xDelta_a = p2.x - p1.x
        yDelta_b = p3.y - p2.y
        xDelta_b = p3.x - p2.x

        try:
            aSlope = yDelta_a / xDelta_a
        except ZeroDivisionError:
            return None

        try:
            bSlope = yDelta_b / xDelta_b
        except ZeroDivisionError:
            return None

        if (math.fabs(xDelta_a) <= epsilon and math.fabs(yDelta_b) <= epsilon):
            m_Center.x = (0.5 * (p2.x + p3.x))
            m_Center.y = (0.5 * (p1.y + p2.y))
            m_dRadius = m_Center.distance(p1)

            return cls(m_Center, m_dRadius)

        if math.fabs(aSlope-bSlope) <= epsilon:
            return None

        m_Center.x = (
                      (aSlope * bSlope * (p1.y - p3.y) +
                       bSlope * (p1.x + p2.x) -
                       aSlope * (p2.x + p3.x)) /
                      (2.0 * (bSlope - aSlope))
                     )
        m_Center.y = (
                      -1.0 * (m_Center.x - (p1.x + p2.x) / 2.0) /
                      aSlope + (p1.y + p2.y) / 2.0
                     )

        m_dRadius = m_Center.distance(p1)

        return cls(m_Center, m_dRadius)

    @classmethod
    def byCenterRadius(cls, pc, radius):
        """Create a CADCircle with 2 points (from radius : CA)
          /------\
         |        |
         A   C    |
         |        |
          \------/
        """
        if not isinstance(pc, (CADPoint, QgsPoint)) or \
           not isinstance(radius, (float, long, int)):
            raise AttributeError

        return cls(pc, radius)

    @classmethod
    def byCenterDiameter(cls, pc, diameter):
        """Create a CADCircle with 2 points (from diameter : AB)
          /------\
         |        |
         A        B
         |        |
          \------/
        """
        if not isinstance(pc, (CADPoint, QgsPoint)) or \
           not isinstance(diameter, (float, long, int)):
            raise AttributeError

        return cls(pc, radius / 2.0)

    @classmethod
    def byCenterPoint(cls, pc, p1):
        """Create a CADCircle by Extent CA
          /------\A
         |        |
         |   C    |
         |        |
          \------/
        """
        if not all(isinstance(p, (QgsPoint, CADPoint)) for p in [p1, pc]):
            raise AttributeError

        p1 = CADPoint(p1)
        pc = CADPoint(pc)

        return cls(pc, pc.distance(p1))
    # Todo: fromTangents

    def exportToQgsGeometry(self, segments=36):
        """Export CADCircle to a QgsGeometry (Polygon)"""
        points = list(self.__iter__(segments))

        return QgsGeometry.fromPolygon([[QgsPoint(p.x, p.y) for p in points]])

    if CIRCSTRING:
        def exportToQgsCircularStringV2(self):
            """Export CADCircle to a QgsCircularStringV2"""
            quadrant = self.quadrant()
            quad = [QgsPointV2(p.x, p.y) for p in quadrant] + \
                   [QgsPointV2(quadrant[0].x, quadrant[0].y)]
            QgsCircString = QgsCircularStringV2()
            QgsCircString.setPoints(quad)

            return QgsCircString
Exemplo n.º 9
0
class CADRegularPolygon(object):
    def __init__(self, pCenter, pCorner, nbEdges=5):
        if not isinstance(pCenter, (QgsPoint, CADPoint)) \
            or not isinstance(pCorner, (QgsPoint, CADPoint)) \
            or not isinstance(nbEdges,
                              (long, int)):
            raise AttributeError
        else:
            self._center = CADPoint(pCenter)
            self._corner = CADPoint(pCorner)
            self._nbEdges = nbEdges
            self.__points = self.__updatePoints()
            # self._angle

    def __str__(self):
        s = "Regular polygon:\n" + \
            "Edges: {}".format(self._nbEdges) + '\n' + \
            "Center: {}".format(self._center) + '\n' + \
            "Corner: {}".format(self._corner) + '\n'
        return s

    def __repr__(self, precision=3):
        s = "CADRegularPolygon("
        s += "QgsPoint(%s)" % self._center
        s += ", QgsPoint(%s)" % self._corner
        s += ", %s)" % self._nbEdges

        return s

    def __eq__(self, other):
        if not isinstance(other, (QgsPoint, CADPoint)):
            raise AttributeError

        if CADPoint.pointsCompare(self._center, other._center) \
                and self._nbEdges == other._nbEdges:
            return True

        return False

    def __iter__(self):
        i = 0
        while i < self._nbEdges:
            yield self.__points[i]
            i += 1

    def __update(self):
        self.__updatePoints()
        self.__updateRadius()
        self.__updateAngle()

    def __updateAngle(self):
        self._angle = self._center.getAngleOfLineBetweenTwoPoints(self._corner)

    def __updateRadius(self):
        self._radius = self._center.distance(self._corner)

    def __updatePoints(self):
        n = 1
        center = self._center
        corner = self._corner

        r = center.distance(corner)

        points = []
        angle_add = 2 * math.pi / self._nbEdges

        angle_start = math.atan2(corner.y - center.y, corner.x - center.x)

        angle = angle_start

        while (n <= self._nbEdges):

            angle += angle_add
            if angle_add > 0.0 and angle > math.pi:
                angle -= 2 * math.pi

            c2 = center.pointProjected(r, math.degrees(angle))

            points.append(c2)

            n += 1

        return points

    @property
    def nbEdges(self):
        """Return the number of sides/edges of the RegularPolygon
        """
        return self._nbEdges

    @nbEdges.setter
    def nbEdges(self, n):
        """Set the number of sides/edges of the RegularPolygon
        """
        if not isinstance(n, (int, long)):
            raise AttributeError
        self._nbEdges = n
        self.__update()

    @property
    def center(self):
        """The center of the RegularPolygon
        This is also the center of the circumscribing circle.
        """
        return self._center

    @center.setter
    def center(self, pc):
        """Set the center of the RegularPolygon
        """
        if not isinstance(pc, (QgsPoint, CADPoint)):
            raise AttributeError

        angle_exist = self._rotation
        dist_exist = self._radius
        self._center = CADPoint(pc)
        self._corner = self._center.pointProjected(dist_exist, angle_exist)
        self._update()

    @property
    def circumcenter(self):
        """
        Alias for center.
        """
        return self.center

    @property
    def corner(self):
        """Return the first corner (edge) of the RegularPolygon
        """
        return self._corner

    @corner.setter
    def corner(self, pc):
        """Set the first corner (edge) of the RegularPolygon
        """
        if not isinstance(pc, (QgsPoint, CADPoint)):
            raise AttributeError
        self._corner = CADPoint(pc)
        self.__update()

    @property
    def length(self):
        """Return the length of the sides.
        """
        return self._radius * 2 * math.sin(math.pi / self._nbEdges)

    @property
    def radius(self):
        """Radius of the RegularPolygon
        This is also the radius of the circumscribing circle.
        """
        return self._radius

    @property
    def circumradius(self):
        """
        Alias for radius.
        """
        return self.radius

    @property
    def angle(self):
        """Angle by which the RegularPolygon is rotated
        """
        return self._angle

    @property
    def apothem(self):
        """The inradius of the RegularPolygon.
        The apothem/inradius is the radius of the inscribed circle.
        """
        return self.radius * math.cos(math.pi / self._nbEdges)

    @property
    def inradius(self):
        """
        Alias for apothem.
        """
        return self.apothem

    @property
    def interior_angle(self):
        """Measure of the interior angles.
        """
        return (self._nbEdges - 2) * math.pi / self._nbEdges

    @property
    def exterior_angle(self):
        """Measure of the exterior angles.
        """
        return 2 * math.pi / self._nbEdges

    @property
    def circumcircle(self):
        """The circumcircle of the RegularPolygon.
        """
        return CADCircle(self.center, self.radius)

    @property
    def incircle(self):
        """The incircle of the RegularPolygon.
        """
        return CADCircle(self.center, self.apothem)

    @property
    def area(self):
        """Returns the area.
        """
        r, n, l = self._radius, self._nbEdges, self.length
        return r * n * l**2 / (4 * math.tan(math.pi / n))

    @classmethod
    def by2Corners(cls, p1, p2, nbEdges=5):
        """CADRegularPolygon by 2 corners (AB):
           A----B
          /      \
         /        \
         \        /
          \------/
          """
        if not isinstance(p1, (QgsPoint, CADPoint)) or \
           not isinstance(p2, (QgsPoint, CADPoint)) or \
           not isinstance(nbEdges, (long, int)):
            raise AttributeError
        else:
            p1 = CADPoint(p1)
            p2 = CADPoint(p2)
            angle_exist = p1.getAngleOfLineBetweenTwoPoints(p2)
            pm = p1.midpoint(p2)
            length = p1.distance(pm)

            angle = (180.0 - (360.0 / nbEdges)) / 2.0
            hypo = length / math.cos(math.radians(angle))
            pc = p1.pointProjected(hypo, angle_exist + angle)

            return cls(pc, p1, nbEdges)

        return None

    @classmethod
    def byCenterAndCorner(cls, p1, p2, nbEdges=5):
        """CADRegularPolygon by center C and a corner A:
           A-----
          /      \
         /    C   \
         \        /
          \------/
          """
        if not isinstance(p1, (QgsPoint, CADPoint)) or \
           not isinstance(p2, (QgsPoint, CADPoint)) or \
           not isinstance(nbEdges, (long, int)):
            raise AttributeError
        else:
            return cls(p1, p2, nbEdges)

        return None

    def exportToQgsGeometry(self):
        """Export CADRegularPolygon to a QgsGeometry (Polygon)"""
        return QgsGeometry.fromPolygon(
            [[QgsPoint(p.x, p.y) for p in self.__points]])