def __init__(self): self.center = Point2D() self.leftFlank = Segment2D() self.rightFlank = Segment2D() self.leftRear = Segment2D() self.rightRear = Segment2D() self.radius = 0.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
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)
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
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
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
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
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
def GetIntersectableSegments(self): ret = [Segment2D(self._shape2D[0], self._shape2D[1]), Segment2D(self._shape2D[2], self._shape2D[3])] return ret
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 """
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
def GetExteriorSegment(self): return Segment2D(self._shape2D[0], self._shape2D[1])
def GetMidPoint(self): seg = Segment2D(self.GetStartPosition(), self.GetEndPosition()) return seg.GetMidPoint()
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)
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" )
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
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()))