Exemplo n.º 1
0
 def __init__(self):
     self.center = Point2D()
     self.leftFlank = Segment2D()
     self.rightFlank = Segment2D()
     self.leftRear = Segment2D()
     self.rightRear = Segment2D()
     self.radius = 0.0
Exemplo n.º 2
0
    def GetHolesSegmentList(self):
        # Return a list of 2D segments over the wall and on the holes (if any)
        ret = []

        wallvec = self.__construction.GetWallVector()
        startpos = self.__construction.GetStartPosition()

        j = 0
        while (j < self.__tilesSize["columns"]):

            i = int(self.__tilesSize["rows"] - 1)
            found = False
            while ((i >= 0) and not found):

                if (self.__tiles[i][j].IsHole()):
                    found = True

                    p1 = startpos.Copy()
                    p1.Move(wallvec, j * self.__tileDims["width"])
                    p2 = p1.Copy()
                    p2.Move(wallvec, self.__tileDims["width"])
                    seg = Segment2D(p1, p2)
                    ret.append(seg)

                i -= 1

            j += 1

        return ret
Exemplo n.º 3
0
    def DistanceFromPoint(self, posfrom, squared=False):
        # Calculate the distance from given point to wall
        # Work in 2D to simplify

        p = Point2D(posfrom.x, posfrom.y)
        seg = Segment2D(self.GetStartPosition(), self.GetEndPosition())
        return seg.DistanceToPoint(p, squared)
Exemplo n.º 4
0
    def Project(self, position=Point3D(), wallside=1):
        # Projects given position over the exterior wall
        # If wallside is 1, projects over exterior wall. If it is 2, projects over the back wall side. Finally, if it is 3, projects over the medial axis
        # This is usually used when an attacker needs to be attached to the wall to climb it

        p = Point2D().SetFrom3D(position)

        if wallside == 1:
            prj = self.GetExteriorSegment().ProjectPoint(p)
        elif wallside == 2:
            seg = Segment2D(self._shape2D[3], self._shape2D[2])
            prj = seg.ProjectPoint(p)
        elif wallside == 3:
            seg = Segment2D(self.GetStartPosition(), self.GetEndPosition())
            prj = seg.ProjectPoint(p)
        else:
            return None

        position.x = prj.x
        position.y = prj.y

        return position
Exemplo n.º 5
0
    def IntersectAxis(self, segment):
        # Returns the intersection point between given segment and any river axis segment, or none

        i = 0
        while (i < len(self.__axis)):

            s = Segment2D(self.__axis[i - 1], self.__axis[i])
            pnt = s.Intersect(segment)
            if (pnt != None):
                return pnt
            i += 1

        return None
Exemplo n.º 6
0
    def GetGatewaySegmentList(self):
        # Return a list of 2D segments over the wall and on the gateways (if any)
        ret = []

        wallvec = self.__construction.GetWallVector()
        startpos = self.__construction.GetStartPosition()

        for j in self.__gateways:

            p1 = startpos.Copy()
            p1.Move(wallvec, j * self.__tileDims["width"])
            p2 = p1.Copy()
            p2.Move(wallvec, self.__tileDims["width"])
            seg = Segment2D(p1, p2)
            ret.append(seg)

        return ret
Exemplo n.º 7
0
    def GetClosestAxisSegment(self, point):
        # Returns the closest axis segment to given point

        mindist = float('inf')
        seg = None

        i = 0
        while (i < len(self.__axis)):

            s = Segment2D(self.__axis[i - 1], self.__axis[i])
            dist = s.DistanceToPoint(point)
            if (dist < mindist):
                seg = s
                mindist = dist

            i += 1

        return seg
Exemplo n.º 8
0
    def SetPosition(self, p1, p2, reshape=True):
        # Sets the wall position with 2 points. If reshape is true, the wall 2D shape is recalculated

        if p1.Distance(p2) < 5:
            print "WARNING: Too short wall creation"
            # return False

        del self._axis2D[:]
        self._axis2D.append(Segment2D(p1, p2))

        # Generate the wall shape
        if reshape:
            self.JoinShape(None)

        # Recalculates the battalion grid (creates an empty battalion grid)
        # Note that battalion grid is created over wall axis. The wall shape is not taken into account
        self._defendingLines.SetDefendingLine(0, self._axis2D[0])

        # Recalculates the tiles
        self.__tilesManager.RecalculateTiles()

        # Recalculates the 3D rectangle and bounds (used to check shoot hits on wall)
        # Calculate the exterior wall 3D rectangle
        self.__rectangle3D[0] = Point3D(self.GetStartPosition().x, self.GetStartPosition().y, 0.0)
        # self.__rectangle3D[1] = Point3D(self.GetStartPosition().x, self.GetStartPosition().y, self.__walkway["altitude"])
        # self.__rectangle3D[2] = Point3D(self.GetEndPosition().x, self.GetEndPosition().y, self.__walkway["altitude"])
        self.__rectangle3D[1] = Point3D(self.GetStartPosition().x, self.GetStartPosition().y, self._height)
        self.__rectangle3D[2] = Point3D(self.GetEndPosition().x, self.GetEndPosition().y, self._height)
        self.__rectangle3D[3] = Point3D(self.GetEndPosition().x, self.GetEndPosition().y, 0.0)

        # Calculate the rectangle bounding
        self.__boundingRectangle3D = BoundingBox()
        for p in self.__rectangle3D:
            self.__boundingRectangle3D.InsertPoint(p)

        # Calculate the exterior normal vector
        self.CalculateNormalVector()

        return True
Exemplo n.º 9
0
 def GetIntersectableSegments(self):
     ret = [Segment2D(self._shape2D[0], self._shape2D[1]), Segment2D(self._shape2D[2], self._shape2D[3])]
     return ret
Exemplo n.º 10
0
    def __ConstructHalfMoons(self):
        self.__halfMoons = []
        if (not self.__ravelins):
            print "ERROR: Cannot create the halfmoons without the previously calculated ravelins"
            return

        # The algorithm to create a half-moon follows a similar pattern than ravenlins, and needs some of their data  
        # From each bastion and related ravelins,
        #    - Trace 2 rays from frontal bastion flanks segments
        #    - Trace 2 rays from rear ravelin flanks segments, and intersect with the previous ones
        #    - From the segment between the two intersection points, get the mid point and apply a perpendicular movement to get the center of the inside circle
        #    - From the circle center, move in the same direction than bastion and at some constant value (could be the same distance used for ravelins jug calculation)
        #    - Trace to rays from already calculated jag in the same orientation than previous ravelin rays (but inverted direction)
        #    - Intersect the previous rays with the initial bastion rays
        #    - Construct the halfmoon flanks with the segments between previous intersection points and the jag (remember to consider the same orientation than ravelins and bastions)
        #    - Construct the interior halfcircle
        #    - Close the shape by adding small rear segments
        #
        # If there arent related ravelins the halfmoon cannot be constructed with this method. If there are only one, it can be constructed changing the initial steps:
        #    - Trace the bastion ray related with ravelin ray (first step of original algorithm, but only by one side)
        #    - Extend the other bastion segment the distance between intersected point and bastion jag
        #    - Construct the segment between both points
        #    - From here, the algorithm is the same
        #
        # NOTE: In fact, there are only two direction vectors to work, so the bastion flanks directions are the same than rear ravelin flanks directions (see ravelin code)
        #   

        # Get the list of bastions
        blist = self.__castle.GetBastionsList()
        if (not blist):
            return

        for bastion in blist:
            # Get the element with bastion and related ravelins
            if (not bastion.GetLabel() in self.__bastions):
                continue
            belement = self.__bastions[bastion.GetLabel()]
            if (not belement):
                continue

            halfmoon = HalfMoon()

            # Create the rays from bastion flanks and ravelins

            flankbastionright = bastion.GetFlankSegment(right=True, front=True)
            flankbastionleft = bastion.GetFlankSegment(right=False, front=True)
            brayleft = Ray2D(origin=flankbastionleft.p1, direction=flankbastionleft.GetDirection())
            brayright = Ray2D(origin=flankbastionright.p2, direction=flankbastionright.GetDirection())

            # There are only two vector directions that math with bastion flank directions
            leftvector = flankbastionleft.GetDirection()
            rightvector = flankbastionright.GetDirection().Invert()  # Note that both directions are focused to the bastion jag

            if (not belement.leftRavelin and not belement.rightRavelin):
                # Not enough data to construct the halfmoon
                continue

            elif (not belement.leftRavelin):

                rrayright = Ray2D(origin=belement.rightRavelin.leftRear.p1, direction=rightvector)

                # Intersect both rays
                if (not brayleft.HitRay(rrayright)):
                    print "ERROR: Halfmoon cannot be constructed - code 1"
                    continue

                halfmoon.rightRear.p2 = brayleft.GetHitPoint()

                # Extend the right bastion flank at same distance than ray hit from left flank
                dist = flankbastionleft.p2.Distance(halfmoon.rightRear.p2)
                halfmoon.leftRear.p1 = flankbastionright.p1.Copy()
                halfmoon.leftRear.p1.Move(rightvector, dist)


            elif (not belement.rightRavelin):

                rrayleft = Ray2D(origin=belement.leftRavelin.rightRear.p2, direction=leftvector)
                if (not brayright.HitRay(rrayleft)):
                    print "ERROR: Halfmoon cannot be constructed - code 2"
                    continue
                halfmoon.leftRear.p1 = brayright.GetHitPoint()

                # Extend the right bastion flank at same distance than ray hit from left flank
                dist = flankbastionright.p1.Distance(halfmoon.leftRear.p1)
                halfmoon.rightRear.p2 = flankbastionleft.p2.Copy()
                halfmoon.rightRear.p2.Move(leftvector, dist)


            else:

                rrayleft = Ray2D(origin=belement.leftRavelin.rightRear.p2, direction=leftvector)
                rrayright = Ray2D(origin=belement.rightRavelin.leftRear.p1, direction=rightvector)

                # Intersect each pair of rays
                if (not brayleft.HitRay(rrayright)):
                    print "ERROR: Halfmoon cannot be constructed - code 1"
                    continue
                if (not brayright.HitRay(rrayleft)):
                    print "ERROR: Halfmoon cannot be constructed - code 2"
                    continue

                halfmoon.leftRear.p1 = brayright.GetHitPoint()
                halfmoon.rightRear.p2 = brayleft.GetHitPoint()

            # Get the halfmoon center (the center of the interior circle) and radius
            baseseg = Segment2D(halfmoon.leftRear.p1, halfmoon.rightRear.p2)
            halfmoon.center = baseseg.GetMidPoint()
            halfmoon.center.Move(baseseg.GetNormal().Invert(), self.__data.HalfMoonCircleOffset)
            halfmoon.radius = halfmoon.center.Distance(halfmoon.leftRear.p1)

            # Get the frontal jag from center
            jag = halfmoon.center.Copy()
            jag.Move(baseseg.GetNormal(), self.__data.HalfMoonLength)

            # Calculate the flanks and close the shape
            frayleft = Ray2D(origin=jag, direction=leftvector.Copy().Invert())
            frayright = Ray2D(origin=jag, direction=rightvector.Copy().Invert())
            if (not frayleft.HitRay(brayright)):
                print "ERROR: Halfmoon cannot be constructed - code 3"
                continue
            if (not frayright.HitRay(brayleft)):
                print "ERROR: Halfmooon cannot be constructed - code 4"
                continue

            halfmoon.leftRear.p2 = frayleft.GetHitPoint()
            halfmoon.rightRear.p1 = frayright.GetHitPoint()
            halfmoon.leftFlank = Segment2D(halfmoon.leftRear.p2, jag)
            halfmoon.rightFlank = Segment2D(jag, halfmoon.rightRear.p1)

            # Before adding the halfmoon, check if it intersects any other ravelin. This could happens if the castle shape is strange or there are too much distance between bastions
            error = False
            for rv in self.__ravelins:
                if (rv.Intersect(halfmoon)):
                    print "ERROR: Halfmoon cannot be constructed - code 5"
                    error = True
                    break

            if (not error):
                for hm in self.__halfMoons:
                    if (hm.Intersect(halfmoon)):
                        print "ERROR: Halfmoon cannot be constructed - code 6"
                        error = True
                        break

                if (not error):
                    self.__halfMoons.append(halfmoon)
                    self.__bastions[bastion.GetLabel()].halfMoon = halfmoon

            """
Exemplo n.º 11
0
    def __CreatePlacesOfArmsOnCovertWay(self):

        # The algorithm follows next steps:
        #    - Search all non-convex vertices
        #    - For each one, creates 2 new vertices, one for each related segment, at constant length from the vertex
        #    - From the new vertices trace 2 rays parallel to the opposite segments
        #    - Get the intersection point as the place jag
        #    - Remove the non-convex vertex and update the polygon
        #

        poly = self.__covertWay.extShape.Copy()
        self.__covertWay.extShape = Polygon2D()

        i = 0
        while (i < len(poly.shape)):
            s1 = poly.shape[i]
            if ((i + 1) == len(poly.shape)):
                inext = 0
            else:
                inext = i + 1
            s2 = poly.shape[inext]

            # Check the convexity
            if (s1.ConvexTo(s2) or (s1.GetLength() <= self.__data.CovertWayPlacesOfArmsLength) or (
                    s2.GetLength() <= self.__data.CovertWayPlacesOfArmsLength)):
                self.__covertWay.extShape.shape.append(s1)
            else:

                # Create the place of arms

                # Left side
                pleft = s1.p2.Copy()
                pleft.Move(s1.GetDirection().Invert(), self.__data.CovertWayPlacesOfArmsLength)

                # Right side
                pright = s1.p2.Copy()
                pright.Move(s2.GetDirection(), self.__data.CovertWayPlacesOfArmsLength)

                # Jag
                rleft = Ray2D(origin=pleft, direction=s2.GetDirection())
                rright = Ray2D(origin=pright, direction=s1.GetDirection().Invert())
                if (not rleft.HitRay(rright)):
                    print "ERROR: Cannot create the place of arms"
                    i += 1
                    continue
                jag = rleft.GetHitPoint()

                # Get the new segments
                ss1 = Segment2D(s1.p1, pleft)
                sleft = Segment2D(pleft, jag)
                sright = Segment2D(jag, pright)
                ss2 = Segment2D(pright, s2.p2)

                # Update the shape
                self.__covertWay.extShape.shape.extend([ss1, sleft, sright])

                # The last segment cannot be updated yet, so we need to check the convexity with the next segment
                poly.shape[inext] = ss2
                if (inext == 0):
                    self.__covertWay.extShape.shape[0] = ss2

            i += 1
Exemplo n.º 12
0
 def GetExteriorSegment(self):
     return Segment2D(self._shape2D[0], self._shape2D[1])
Exemplo n.º 13
0
 def GetMidPoint(self):
     seg = Segment2D(self.GetStartPosition(), self.GetEndPosition())
     return seg.GetMidPoint()
Exemplo n.º 14
0
    def JoinShape(self, obj, invert=False):
        # Creates and join current shape with given object's shape
        # Note the order of objects: "Current wall is going to be joined with given object". This means that only is calculated the ending wall join
        # The invert flag changes this behaviour (only for towers -> TODO: Also for walls)

        factory = ConstructionFactory()

        if obj == None:
            # None object to join. Constructs a simple rectangular wall shape

            del self._shape2D[0:len(self._shape2D)]

            l = self.GetLength()
            vector = Vector2D()
            vector.CreateFrom2Points(self.GetStartPosition(), self.GetEndPosition())
            tvector = vector.Copy()
            tvector.Rotate(-90)

            p = self.GetStartPosition().Copy()
            p.Move(tvector, self._thickness / 2)
            self._shape2D.append(p.Copy())
            p.Move(vector, l)
            self._shape2D.append(p.Copy())
            p.Move(tvector, -self._thickness)
            self._shape2D.append(p.Copy())
            p.Move(vector, -l)
            self._shape2D.append(p.Copy())

            return

        else:

            # Updates the adjacencies

            if invert:
                self._adjacentConstructions[0] = obj
                obj._adjacentConstructions[1] = self
            else:
                self._adjacentConstructions[1] = obj
                obj._adjacentConstructions[0] = self

        if factory.IsWall(obj):

            # Calculate the bisector between both walls
            bisecang = self.GetBisector(obj)

            # The join point will be along the bisector 
            d = (self._thickness / 2.0) / math.cos(
                math.radians(bisecang["angle"] / 2.0))  # WARNING: We consider all walls of same thickness
            p = self.GetEndPosition().Copy()
            p.Move(bisecang["bisector"], d)

            self._shape2D[1] = p.Copy()
            obj._shape2D[0] = p.Copy()

            p.Move(bisecang["bisector"], -(d * 2.0))
            self._shape2D[2] = p.Copy()
            obj._shape2D[3] = p.Copy()

            self._adjacentConstructions[1] = obj
            obj._adjacentConstructions[0] = self




        elif factory.IsSquaredTower(obj):

            # Calculate the intersection points of wall shape with tower   

            # We must consider the invert flag. If it is true, the joined part will be the starting wall. Otherwise, the ending wall
            if invert:
                v = Vector3D().SetFrom2D(self.GetWallVector())
                v.Invert()
                ray1 = Ray(origin=Point3D().SetFrom2D(self._shape2D[1]), direction=v)
                ray2 = Ray(origin=Point3D().SetFrom2D(self._shape2D[2]), direction=v)
            else:
                v = Vector3D().SetFrom2D(self.GetWallVector())
                ray1 = Ray(origin=Point3D().SetFrom2D(self._shape2D[0]), direction=v)
                ray2 = Ray(origin=Point3D().SetFrom2D(self._shape2D[3]), direction=v)

            int1 = obj.RecieveImpact(ray1)
            int2 = obj.RecieveImpact(ray2)

            if int1 != None:
                if invert:
                    self._shape2D[0] = Point2D().SetFrom3D(int1)
                else:
                    self._shape2D[1] = Point2D().SetFrom3D(int1)
            if int2 != None:
                if invert:
                    self._shape2D[3] = Point2D().SetFrom3D(int2)
                else:
                    self._shape2D[2] = Point2D().SetFrom3D(int2)

            # Reshape the wall axis (and all dependant data). Get the medium points of side shape segments
            mp1 = Segment2D(self._shape2D[0], self._shape2D[3]).GetMidPoint()
            mp2 = Segment2D(self._shape2D[1], self._shape2D[2]).GetMidPoint()
            self.SetPosition(mp1, mp2, reshape=False)


        elif factory.IsRoundedTower(obj):

            # Calculate the intersection points of wall shape with tower   

            # We must consider the invert flag. If it is true, the joined part will be the starting wall. Otherwise, the ending wall
            if invert:
                v = Vector3D().SetFrom2D(self.GetWallVector())
                v.Invert()
                ray1 = Ray(origin=Point3D().SetFrom2D(self._shape2D[1]), direction=v)
                ray2 = Ray(origin=Point3D().SetFrom2D(self._shape2D[2]), direction=v)
            else:
                v = Vector3D().SetFrom2D(self.GetWallVector())
                ray1 = Ray(origin=Point3D().SetFrom2D(self._shape2D[0]), direction=v)
                ray2 = Ray(origin=Point3D().SetFrom2D(self._shape2D[3]), direction=v)

            int1 = obj.RecieveImpact(ray1)
            int2 = obj.RecieveImpact(ray2)

            if int1 != None:
                if invert:
                    self._shape2D[0] = Point2D().SetFrom3D(int1)
                else:
                    self._shape2D[1] = Point2D().SetFrom3D(int1)
            if int2 != None:
                if invert:
                    self._shape2D[3] = Point2D().SetFrom3D(int2)
                else:
                    self._shape2D[2] = Point2D().SetFrom3D(int2)

            # Reshape the wall axis (and all dependant data). Get the medium points of side shape segments
            mp1 = Segment2D(self._shape2D[0], self._shape2D[3]).GetMidPoint()
            mp2 = Segment2D(self._shape2D[1], self._shape2D[2]).GetMidPoint()
            self.SetPosition(mp1, mp2, reshape=False)


        elif factory.IsBastion(obj):
            # Fit the wall to the bastion

            if invert:
                self._shape2D[3] = obj.GetEndPosition(exterior=False)
                self._shape2D[0] = obj.GetEndPosition(exterior=True)
            else:
                self._shape2D[1] = obj.GetStartPosition(exterior=True)
                self._shape2D[2] = obj.GetStartPosition(exterior=False)

            # Reshape the wall axis (and all dependant data). Get the medium points of side shape segments
            mp1 = Segment2D(self._shape2D[0], self._shape2D[3]).GetMidPoint()
            mp2 = Segment2D(self._shape2D[1], self._shape2D[2]).GetMidPoint()
            self.SetPosition(mp1, mp2, reshape=False)
Exemplo n.º 15
0
    def DrawBattalion(self, battalion, canvas, viewport, canvasobjs):
        # Draws battalion
        # NOTE: The canvas objects updating is delegated to Battalion class, so all drawn objects must be returned into canvasobjs list

        # Search the battalion index
        index = self.GetDefendingBattalionIndex(battalion)
        if (index == -1):
            print "ERROR: Battalion dont found for DrawBattalion"
            return

        db = self._battalions[index]

        factory = ArmyFactory()
        if (factory.IsArcher(battalion)):

            # Draw an archer

            v = Vector2D().CreateFrom2Points(self.__center, db.position)
            v.Rotate(90)

            p1 = Point2D().SetFrom3D(db.position.Copy())
            p1.Move(v, -(self._gridCellSize / 2.0))
            p2 = p1.Copy()
            p2.Move(v, self._gridCellSize)
            p3 = p2.Copy()
            v2 = Vector2D().CreateFrom2Points(self.__center, p2)
            p3.Move(v2, -(self._width))
            p4 = p1.Copy()
            v3 = Vector2D().CreateFrom2Points(self.__center, p1)
            p4.Move(v3, -(self._width))

            pv1 = viewport.W2V(p1)
            pv2 = viewport.W2V(p2)
            pv3 = viewport.W2V(p3)
            pv4 = viewport.W2V(p4)

            canvasobjs.append(
                canvas.create_polygon(
                    (pv1.x, pv1.y, pv2.x, pv2.y, pv3.x, pv3.y, pv4.x, pv4.y),
                    fill="blue",
                    outline="cyan"))

            if (Battles.Utils.Settings.SETTINGS.Get_B(category='Castle',
                                                      tag='ShowLabels')):
                # Deploy the avaiable troops number inside rectangle
                t = Segment2D(p1, p3).GetMidPoint()
                tp = viewport.W2V(t)
                canvasobjs.append(
                    canvas.create_text(tp.x,
                                       tp.y,
                                       text=int(db.battalion.GetNumber()),
                                       fill="cyan"))

        elif (factory.IsCannon(battalion)):

            # Draw a cannon

            v = Vector2D().CreateFrom2Points(self.__center, db.position)
            v.Rotate(90)

            p1 = Point2D().SetFrom3D(db.position.Copy())
            p1.Move(v, -(self._gridCellSize / 2.0))
            p2 = p1.Copy()
            p2.Move(v, self._gridCellSize)
            p3 = p2.Copy()
            v2 = Vector2D().CreateFrom2Points(self.__center, p2)
            p3.Move(v2, -(self._width))
            p4 = p1.Copy()
            v3 = Vector2D().CreateFrom2Points(self.__center, p1)
            p4.Move(v3, -(self._width))

            pv1 = viewport.W2V(p1)
            pv2 = viewport.W2V(p2)
            pv3 = viewport.W2V(p3)
            pv4 = viewport.W2V(p4)

            canvasobjs.append(
                canvas.create_polygon(
                    (pv1.x, pv1.y, pv2.x, pv2.y, pv3.x, pv3.y, pv4.x, pv4.y),
                    fill="DarkBlue",
                    outline="cyan"))

            if (Battles.Utils.Settings.SETTINGS.Get_B(category='Castle',
                                                      tag='ShowLabels')):
                # Deploy the avaiable troops number inside rectangle
                t = Segment2D(p1, p3).GetMidPoint()
                tp = viewport.W2V(t)
                canvasobjs.append(
                    canvas.create_text(tp.x,
                                       tp.y,
                                       text=int(db.battalion.GetNumber()),
                                       fill="cyan"))
        else:

            print(
                "ERROR: DefendingLineRounded.Draw -> Battalion not defined yet"
            )
Exemplo n.º 16
0
    def __ConstructRavelins(self):

        self.__ravelins = []

        # The ravelin is constucted parametrically with bastion data and some constant values. It can be seen as two triangles, the bottom one, smaller, and the external, larger
        # The algorithm to get the ravelin center is:
        #    - Trace a segment between the bastion external vertices
        #    - Get the intersection between the two vectors related to the bastion flanks
        #    - Trace a wall perpendicular line from last intersection point. Get the intersection with the first segment. This is the center of the ravelin
        # The algorithm to get the front flanks is:
        #    - Trace a line from bastion vertices (those between front and rear flanks) at a constant angle value from the front flanks (never less than 90 degrees)
        #    - Get the lines intersection
        #    - Get the lines intersections with the first segment of previous algorithm
        #    - The external/front flanks are the segments between the intersection points
        # The algorithm to get the internal flanks is:
        #    - Trace a line from each previous intersection points at wall direction and with same front bastion flank
        #    - Get the intersection point between lines
        #    - The internal/rear flanks are the segments between the intersection points
        #
        #
        # But wait!. There are a problem with this algorithm. If the fortress is not symmetric, or the bastions are placed too far from each one, the ravelin becomes too large.
        # For that reason, a new method is defined 
        #
        # The method is the same, but not the flanks construction. In place of taking the bastion flank angle, choose a maximum distance from ravelin center and frontal vertex
        #
        # Finally, consider the ravelin shape segments to be constructed in the same direction than bastions, just to make it easy if in the future the ravelin shape must be queried
        #

        # Get each pair of castle bastions
        blist = self.__castle.GetBastionsList()
        if (not blist):
            return

        i = 0
        while (i < len(blist)):
            bastion1 = blist[i]
            if ((i + 1) >= len(blist)):
                bastion2 = blist[0]
            else:
                bastion2 = blist[i + 1]

            i += 1
            ravelin = Ravelin()

            # Calculate the ravelin center point
            flankseg1 = bastion1.GetFlankSegment(right=True, front=True)
            flankseg2 = bastion2.GetFlankSegment(right=False, front=True)

            bsegment = Segment2D(flankseg1.p1, flankseg2.p2)

            r1 = Ray2D(origin=flankseg1.p1, direction=flankseg1.GetDirection())
            r2 = Ray2D(origin=flankseg2.p2, direction=flankseg2.GetDirection().Invert())
            if (not r1.HitRay(r2)):
                print "ERROR: Ravelin cannot be constructed - code 1"
                continue

            r3 = Ray2D(origin=r1.GetHitPoint(),
                       direction=bastion2.GetFlankSegment(right=False, front=False).GetDirection())
            if (not r3.HitSegment(bsegment)):
                print "ERROR: Ravelin cannot be constructed - code 2"
                continue

            ravelin.center = r3.GetHitPoint()

            if (Battles.Utils.Settings.SETTINGS.Get_I('Castle', 'StarFortress', 'Ravelin/Method') == 1):
                # DEPRECATED!!!!
                # Calculate the front flanks

                # Rotate the bastion flanks segment vectors
                vec1 = flankseg1.GetDirection()
                vec1.Rotate(Battles.Utils.Settings.SETTINGS.Get_F('Castle', 'StarFortress', 'Ravelin/BastionAngle'))
                vec2 = flankseg2.GetDirection()
                vec2.Rotate(-Battles.Utils.Settings.SETTINGS.Get_F('Castle', 'StarFortress', 'Ravelin/BastionAngle'))

                # Intersect both vectors
                rr1 = Ray2D(origin=flankseg1.p2, direction=vec1)
                rr2 = Ray2D(origin=flankseg2.p1, direction=vec2)
                if (not rr1.HitRay(rr2)):
                    print "ERROR: Ravelin cannot be constructed - code 3"
                    continue

                ravelinexternalvertex = rr1.GetHitPoint()

                # Intersect each vector with ravelin base segment
                rr1.Reset()
                if (not rr1.HitSegment(bsegment)):
                    print "ERROR: Ravelin cannot be constructed - code 4"
                    continue
                if (not rr2.HitSegment(bsegment)):
                    print "ERROR: Ravelin cannot be constructed - code 5"
                    continue

                ravelin.leftFlank = Segment2D(rr1.GetHitPoint(), ravelinexternalvertex)
                ravelin.rightFlank = Segment2D(ravelinexternalvertex, rr2.GetHitPoint())

            elif (Battles.Utils.Settings.SETTINGS.Get_I('Castle', 'StarFortress', 'Ravelin/Method') == 2):

                # Extend the ravelincenter to defined radius

                ravelinexternalvertex = ravelin.center.Copy()
                vec = bastion2.GetFlankSegment(right=False, front=False).GetDirection()
                ravelinexternalvertex.Move(vec, self.__data.RavelinRadius)

                # Considering the segments between frontal vertex and previous bastion vertices, calculate the intersection points with the rays used to calculcate the ravelin center
                rrs1 = Ray2D(origin=ravelinexternalvertex,
                             direction=Vector2D().CreateFrom2Points(flankseg1.p2, ravelinexternalvertex))
                rrs2 = Ray2D(origin=ravelinexternalvertex,
                             direction=Vector2D().CreateFrom2Points(flankseg2.p1, ravelinexternalvertex))
                if (not rrs1.HitSegment(bsegment)):
                    print "ERROR: Ravelin cannot be constructed - code 6"
                    continue
                if (not rrs2.HitSegment(bsegment)):
                    print "ERROR: Ravelin cannot be constructed - code 7"
                    continue

                ravelin.leftFlank = Segment2D(rrs1.GetHitPoint(), ravelinexternalvertex)
                ravelin.rightFlank = Segment2D(ravelinexternalvertex, rrs2.GetHitPoint())


            else:
                print "ERROR: Ravelin method not defined"
                return

            # Finally, calculate the rear ravelin segments
            rb1 = Ray2D(origin=ravelin.leftFlank.p1, direction=flankseg1.GetDirection())
            rb2 = Ray2D(origin=ravelin.rightFlank.p2, direction=flankseg2.GetDirection().Invert())
            if (not rb1.HitRay(rb2)):
                print "ERROR: Ravelin cannot be constructed - code 10"
                continue
            ravelin.leftRear = Segment2D(rb1.GetHitPoint(), ravelin.leftFlank.p1)
            ravelin.rightRear = Segment2D(ravelin.rightFlank.p2, rb1.GetHitPoint())

            # A final check allow or not the ravelin construction if it is too small
            if (ravelin.rightRear.p1.Distance(ravelin.leftRear.p2) >= self.__data.RavelinMinWidth):

                self.__ravelins.append(ravelin)

                # Updates the starfortress structure
                if (not self.__bastions.has_key(bastion1.GetLabel())):
                    elem1 = StarFortressElement()
                    elem1.bastion = bastion1
                    elem1.rightRavelin = ravelin
                    self.__bastions[bastion1.GetLabel()] = elem1
                else:
                    self.__bastions[bastion1.GetLabel()].rightRavelin = ravelin

                if (not self.__bastions.has_key(bastion2.GetLabel())):
                    elem2 = StarFortressElement()
                    elem2.bastion = bastion2
                    elem2.leftRavelin = ravelin
                    self.__bastions[bastion2.GetLabel()] = elem2
                else:
                    self.__bastions[bastion2.GetLabel()].leftRavelin = ravelin
Exemplo n.º 17
0
    def __CreateShape(self, polyline):

        # Expand the polyline with the current width to construct a bounding polygon

        # Calculate the set of vectors to expand the polyline vertices
        # For the first and last vertices we use the perpendicular vectors. For the others, the bisector

        if (len(polyline) < 2):
            print "ERROR: Given polyline is not enough to construct the river"
            return

        vecs = [Segment2D(polyline[0], polyline[1]).GetNormal()]

        i = 1
        while (i < (len(polyline) - 1)):
            v1 = Vector2D().CreateFrom2Points(polyline[i - 1], polyline[i])
            v1.Rotate(-90)
            v2 = Vector2D().CreateFrom2Points(polyline[i], polyline[i + 1])
            v2.Rotate(-90)
            vecs.append(v1.Bisector(v2))
            i += 1

        vecs.append(Segment2D(polyline[-2], polyline[-1]).GetNormal())

        # Move each polyline vertex using the vectors to get the polygon set of segments

        # Top edge (there isnt any top or bottom, its just an orientative consideration)
        i = 0
        plast = Point2D()
        while (i < len(polyline)):
            p = polyline[i].GetMove(vecs[i], self.__width)
            if (i > 0):
                self.__shape.shape.append(Segment2D(plast, p))
            plast = p
            i += 1

        # Right edge
        p1 = polyline[-1]
        p2 = p1.Copy()
        self.__shape.shape.append(
            Segment2D(p1.GetMove(vecs[-1], self.__width),
                      p2.GetMove(vecs[-1], -self.__width)))

        # Right triangular cap
        seg = self.__shape.shape[-1]
        pcap = polyline[-1].Copy()
        pcap.Move(Vector2D().CreateFrom2Points(polyline[-2], polyline[-1]),
                  self.__width)
        self.__rightCap.shape.append(seg.Copy())
        self.__rightCap.shape.append(Segment2D(seg.p2.Copy(), pcap))
        self.__rightCap.shape.append(Segment2D(pcap, seg.p1.Copy()))

        # Bottom edge
        i = len(polyline) - 1
        while (i >= 0):
            p = polyline[i].GetMove(vecs[i], -self.__width)
            if (i < (len(polyline) - 1)):
                self.__shape.shape.append(Segment2D(plast, p))
            plast = p
            i -= 1

        # Left edge
        p1 = polyline[0]
        p2 = p1.Copy()
        self.__shape.shape.append(
            Segment2D(p1.GetMove(vecs[0], -self.__width),
                      p2.GetMove(vecs[0], self.__width)))

        # Left triangular cap
        seg = self.__shape.shape[-1]
        pcap = polyline[0].Copy()
        pcap.Move(Vector2D().CreateFrom2Points(polyline[1], polyline[0]),
                  self.__width)
        self.__leftCap.shape.append(seg.Copy())
        self.__leftCap.shape.append(Segment2D(seg.p2.Copy(), pcap))
        self.__leftCap.shape.append(Segment2D(pcap, seg.p1.Copy()))