mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
[2/3] Improve join point placement.
This commit is contained in:
parent
e03d710d53
commit
d444d716f5
@ -1 +1,2 @@
|
|||||||
from .ipzonegeometry import IpZoneGeometry
|
from .ipzonegeometry import IpZoneGeometry
|
||||||
|
from .joinzonegeometry import JoinZoneGeometry
|
||||||
|
|||||||
84
game/flightplan/joinzonegeometry.py
Normal file
84
game/flightplan/joinzonegeometry.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import shapely.ops
|
||||||
|
from dcs import Point
|
||||||
|
from shapely.geometry import Point as ShapelyPoint, Polygon
|
||||||
|
|
||||||
|
from game.theater import ConflictTheater
|
||||||
|
from game.utils import nautical_miles
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from game.coalition import Coalition
|
||||||
|
|
||||||
|
|
||||||
|
class JoinZoneGeometry:
|
||||||
|
"""Defines the zones used for finding optimal join point placement.
|
||||||
|
|
||||||
|
The zones themselves are stored in the class rather than just the resulting join
|
||||||
|
point so that the zones can be drawn in the map for debugging purposes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
target: Point,
|
||||||
|
home: Point,
|
||||||
|
ip: Point,
|
||||||
|
coalition: Coalition,
|
||||||
|
theater: ConflictTheater,
|
||||||
|
) -> None:
|
||||||
|
# Normal join placement is based on the path from home to the IP. If no path is
|
||||||
|
# found it means that the target is on a direct path. In that case we instead
|
||||||
|
# want to enforce that the join point is:
|
||||||
|
#
|
||||||
|
# * Not closer to the target than the IP.
|
||||||
|
# * Not too close to the home airfield.
|
||||||
|
# * Not threatened.
|
||||||
|
# * A minimum distance from the IP.
|
||||||
|
# * Not too sharp a turn at the ingress point.
|
||||||
|
self.ip = ShapelyPoint(ip.x, ip.y)
|
||||||
|
self.threat_zone = coalition.opponent.threat_zone.all
|
||||||
|
self.home = ShapelyPoint(home.x, home.y)
|
||||||
|
|
||||||
|
self.ip_bubble = self.ip.buffer(coalition.doctrine.join_distance.meters)
|
||||||
|
|
||||||
|
ip_distance = ip.distance_to_point(target)
|
||||||
|
self.target_bubble = ShapelyPoint(target.x, target.y).buffer(ip_distance)
|
||||||
|
|
||||||
|
# The minimum distance between the home location and the IP.
|
||||||
|
min_distance_from_home = nautical_miles(5)
|
||||||
|
|
||||||
|
self.home_bubble = self.home.buffer(min_distance_from_home.meters)
|
||||||
|
|
||||||
|
self.excluded_zone = shapely.ops.unary_union(
|
||||||
|
[self.home_bubble, self.ip_bubble, self.target_bubble, self.threat_zone]
|
||||||
|
)
|
||||||
|
|
||||||
|
ip_heading = target.heading_between_point(ip)
|
||||||
|
|
||||||
|
# Arbitrarily large since this is later constrained by the map boundary, and
|
||||||
|
# we'll be picking a location close to the IP anyway. Just used to avoid real
|
||||||
|
# distance calculations to project to the map edge.
|
||||||
|
large_distance = nautical_miles(400).meters
|
||||||
|
turn_limit = 40
|
||||||
|
ip_limit_ccw = ip.point_from_heading(ip_heading - turn_limit, large_distance)
|
||||||
|
ip_limit_cw = ip.point_from_heading(ip_heading + turn_limit, large_distance)
|
||||||
|
|
||||||
|
ip_direction_limit_wedge = Polygon(
|
||||||
|
[
|
||||||
|
(ip.x, ip.y),
|
||||||
|
(ip_limit_ccw.x, ip_limit_ccw.y),
|
||||||
|
(ip_limit_cw.x, ip_limit_cw.y),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.permissible_line = (
|
||||||
|
coalition.nav_mesh.map_bounds(theater)
|
||||||
|
.intersection(ip_direction_limit_wedge)
|
||||||
|
.intersection(self.excluded_zone.boundary)
|
||||||
|
)
|
||||||
|
|
||||||
|
def find_best_join_point(self) -> Point:
|
||||||
|
join, _ = shapely.ops.nearest_points(self.permissible_line, self.home)
|
||||||
|
return Point(join.x, join.y)
|
||||||
@ -20,7 +20,7 @@ from dcs.unit import Unit
|
|||||||
from shapely.geometry import Point as ShapelyPoint
|
from shapely.geometry import Point as ShapelyPoint
|
||||||
|
|
||||||
from game.data.doctrine import Doctrine
|
from game.data.doctrine import Doctrine
|
||||||
from game.flightplan import IpZoneGeometry
|
from game.flightplan import IpZoneGeometry, JoinZoneGeometry
|
||||||
from game.theater import (
|
from game.theater import (
|
||||||
Airfield,
|
Airfield,
|
||||||
ControlPoint,
|
ControlPoint,
|
||||||
@ -949,20 +949,22 @@ class FlightPlanBuilder:
|
|||||||
def regenerate_package_waypoints(self) -> None:
|
def regenerate_package_waypoints(self) -> None:
|
||||||
from gen.ato import PackageWaypoints
|
from gen.ato import PackageWaypoints
|
||||||
|
|
||||||
|
package_airfield = self.package_airfield()
|
||||||
|
|
||||||
# Start by picking the best IP for the attack.
|
# Start by picking the best IP for the attack.
|
||||||
ingress_point = IpZoneGeometry(
|
ingress_point = IpZoneGeometry(
|
||||||
self.package.target.position,
|
self.package.target.position,
|
||||||
self.package_airfield().position,
|
package_airfield.position,
|
||||||
self.coalition,
|
self.coalition,
|
||||||
).find_best_ip()
|
).find_best_ip()
|
||||||
|
|
||||||
# Pick the join point based on the best route to the IP.
|
join_point = JoinZoneGeometry(
|
||||||
join_point = self.preferred_join_point(ingress_point)
|
self.package.target.position,
|
||||||
if join_point is None:
|
package_airfield.position,
|
||||||
# The entire path to the target is threatened. Use the fallback behavior for
|
ingress_point,
|
||||||
# now.
|
self.coalition,
|
||||||
self.legacy_package_waypoints_impl(ingress_point)
|
self.theater,
|
||||||
return
|
).find_best_join_point()
|
||||||
|
|
||||||
# And the split point based on the best route from the IP. Since that's no
|
# And the split point based on the best route from the IP. Since that's no
|
||||||
# different than the best route *to* the IP, this is the same as the join point.
|
# different than the best route *to* the IP, this is the same as the join point.
|
||||||
|
|||||||
@ -12,6 +12,7 @@ from shapely.geometry import LineString, Point as ShapelyPoint, Polygon, MultiPo
|
|||||||
|
|
||||||
from game import Game
|
from game import Game
|
||||||
from game.dcs.groundunittype import GroundUnitType
|
from game.dcs.groundunittype import GroundUnitType
|
||||||
|
from game.flightplan import JoinZoneGeometry
|
||||||
from game.navmesh import NavMesh, NavMeshPoly
|
from game.navmesh import NavMesh, NavMeshPoly
|
||||||
from game.profiling import logged_duration
|
from game.profiling import logged_duration
|
||||||
from game.theater import (
|
from game.theater import (
|
||||||
@ -82,6 +83,12 @@ def shapely_to_leaflet_polys(
|
|||||||
return [shapely_poly_to_leaflet_points(poly, theater) for poly in polys]
|
return [shapely_poly_to_leaflet_points(poly, theater) for poly in polys]
|
||||||
|
|
||||||
|
|
||||||
|
def shapely_line_to_leaflet_points(
|
||||||
|
line: LineString, theater: ConflictTheater
|
||||||
|
) -> list[LeafletLatLon]:
|
||||||
|
return [theater.point_to_ll(Point(x, y)).as_list() for x, y in line.coords]
|
||||||
|
|
||||||
|
|
||||||
class ControlPointJs(QObject):
|
class ControlPointJs(QObject):
|
||||||
nameChanged = Signal()
|
nameChanged = Signal()
|
||||||
blueChanged = Signal()
|
blueChanged = Signal()
|
||||||
@ -822,16 +829,20 @@ class IpZonesJs(QObject):
|
|||||||
def permissibleZone(self) -> list[LeafletPoly]:
|
def permissibleZone(self) -> list[LeafletPoly]:
|
||||||
return self._permissible_zone
|
return self._permissible_zone
|
||||||
|
|
||||||
@Property(list, notify=permissibleZoneChanged)
|
@Property(list, notify=safeZoneChanged)
|
||||||
def safeZone(self) -> list[LeafletPoly]:
|
def safeZone(self) -> list[LeafletPoly]:
|
||||||
return self._safe_zone
|
return self._safe_zone
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def empty(cls) -> IpZonesJs:
|
||||||
|
return IpZonesJs([], [], [], [])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def for_flight(cls, flight: Flight, game: Game) -> IpZonesJs:
|
def for_flight(cls, flight: Flight, game: Game) -> IpZonesJs:
|
||||||
|
if not ENABLE_EXPENSIVE_DEBUG_TOOLS:
|
||||||
|
return IpZonesJs.empty()
|
||||||
target = flight.package.target
|
target = flight.package.target
|
||||||
home = flight.departure
|
home = flight.departure
|
||||||
if not ENABLE_EXPENSIVE_DEBUG_TOOLS or target == home:
|
|
||||||
return IpZonesJs([], [], [], [])
|
|
||||||
geometry = IpZoneGeometry(target.position, home.position, game.blue)
|
geometry = IpZoneGeometry(target.position, home.position, game.blue)
|
||||||
return IpZonesJs(
|
return IpZonesJs(
|
||||||
shapely_to_leaflet_polys(geometry.home_bubble, game.theater),
|
shapely_to_leaflet_polys(geometry.home_bubble, game.theater),
|
||||||
@ -841,6 +852,73 @@ class IpZonesJs(QObject):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class JoinZonesJs(QObject):
|
||||||
|
homeBubbleChanged = Signal()
|
||||||
|
targetBubbleChanged = Signal()
|
||||||
|
ipBubbleChanged = Signal()
|
||||||
|
excludedZoneChanged = Signal()
|
||||||
|
permissibleLineChanged = Signal()
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
home_bubble: list[LeafletPoly],
|
||||||
|
target_bubble: list[LeafletPoly],
|
||||||
|
ip_bubble: list[LeafletPoly],
|
||||||
|
excluded_zone: list[LeafletPoly],
|
||||||
|
permissible_line: list[LeafletLatLon],
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self._home_bubble = home_bubble
|
||||||
|
self._target_bubble = target_bubble
|
||||||
|
self._ip_bubble = ip_bubble
|
||||||
|
self._excluded_zone = excluded_zone
|
||||||
|
self._permissible_line = permissible_line
|
||||||
|
|
||||||
|
@Property(list, notify=homeBubbleChanged)
|
||||||
|
def homeBubble(self) -> list[LeafletPoly]:
|
||||||
|
return self._home_bubble
|
||||||
|
|
||||||
|
@Property(list, notify=targetBubbleChanged)
|
||||||
|
def targetBubble(self) -> list[LeafletPoly]:
|
||||||
|
return self._target_bubble
|
||||||
|
|
||||||
|
@Property(list, notify=ipBubbleChanged)
|
||||||
|
def ipBubble(self) -> list[LeafletPoly]:
|
||||||
|
return self._ip_bubble
|
||||||
|
|
||||||
|
@Property(list, notify=excludedZoneChanged)
|
||||||
|
def excludedZone(self) -> list[LeafletPoly]:
|
||||||
|
return self._excluded_zone
|
||||||
|
|
||||||
|
@Property(list, notify=permissibleLineChanged)
|
||||||
|
def permissibleLine(self) -> list[LeafletLatLon]:
|
||||||
|
return self._permissible_line
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def empty(cls) -> JoinZonesJs:
|
||||||
|
return JoinZonesJs([], [], [], [], [])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def for_flight(cls, flight: Flight, game: Game) -> JoinZonesJs:
|
||||||
|
if not ENABLE_EXPENSIVE_DEBUG_TOOLS:
|
||||||
|
return JoinZonesJs.empty()
|
||||||
|
target = flight.package.target
|
||||||
|
home = flight.departure
|
||||||
|
if flight.package.waypoints is None:
|
||||||
|
return JoinZonesJs.empty()
|
||||||
|
ip = flight.package.waypoints.ingress
|
||||||
|
geometry = JoinZoneGeometry(
|
||||||
|
target.position, home.position, ip, game.blue, game.theater
|
||||||
|
)
|
||||||
|
return JoinZonesJs(
|
||||||
|
shapely_to_leaflet_polys(geometry.home_bubble, game.theater),
|
||||||
|
shapely_to_leaflet_polys(geometry.target_bubble, game.theater),
|
||||||
|
shapely_to_leaflet_polys(geometry.ip_bubble, game.theater),
|
||||||
|
shapely_to_leaflet_polys(geometry.excluded_zone, game.theater),
|
||||||
|
shapely_line_to_leaflet_points(geometry.permissible_line, game.theater),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MapModel(QObject):
|
class MapModel(QObject):
|
||||||
cleared = Signal()
|
cleared = Signal()
|
||||||
|
|
||||||
@ -855,6 +933,7 @@ class MapModel(QObject):
|
|||||||
mapZonesChanged = Signal()
|
mapZonesChanged = Signal()
|
||||||
unculledZonesChanged = Signal()
|
unculledZonesChanged = Signal()
|
||||||
ipZonesChanged = Signal()
|
ipZonesChanged = Signal()
|
||||||
|
joinZonesChanged = Signal()
|
||||||
|
|
||||||
def __init__(self, game_model: GameModel) -> None:
|
def __init__(self, game_model: GameModel) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -871,7 +950,8 @@ class MapModel(QObject):
|
|||||||
self._navmeshes = NavMeshJs([], [])
|
self._navmeshes = NavMeshJs([], [])
|
||||||
self._map_zones = MapZonesJs([], [], [])
|
self._map_zones = MapZonesJs([], [], [])
|
||||||
self._unculled_zones = []
|
self._unculled_zones = []
|
||||||
self._ip_zones = IpZonesJs([], [], [], [])
|
self._ip_zones = IpZonesJs.empty()
|
||||||
|
self._join_zones = JoinZonesJs.empty()
|
||||||
self._selected_flight_index: Optional[Tuple[int, int]] = None
|
self._selected_flight_index: Optional[Tuple[int, int]] = None
|
||||||
GameUpdateSignal.get_instance().game_loaded.connect(self.on_game_load)
|
GameUpdateSignal.get_instance().game_loaded.connect(self.on_game_load)
|
||||||
GameUpdateSignal.get_instance().flight_paths_changed.connect(self.reset_atos)
|
GameUpdateSignal.get_instance().flight_paths_changed.connect(self.reset_atos)
|
||||||
@ -895,7 +975,7 @@ class MapModel(QObject):
|
|||||||
self._navmeshes = NavMeshJs([], [])
|
self._navmeshes = NavMeshJs([], [])
|
||||||
self._map_zones = MapZonesJs([], [], [])
|
self._map_zones = MapZonesJs([], [], [])
|
||||||
self._unculled_zones = []
|
self._unculled_zones = []
|
||||||
self._ip_zones = IpZonesJs([], [], [], [])
|
self._ip_zones = IpZonesJs.empty()
|
||||||
self.cleared.emit()
|
self.cleared.emit()
|
||||||
|
|
||||||
def set_package_selection(self, index: int) -> None:
|
def set_package_selection(self, index: int) -> None:
|
||||||
@ -984,11 +1064,14 @@ class MapModel(QObject):
|
|||||||
) + self._flights_in_ato(self.game.red.ato, blue=False)
|
) + self._flights_in_ato(self.game.red.ato, blue=False)
|
||||||
self.flightsChanged.emit()
|
self.flightsChanged.emit()
|
||||||
selected_flight = self._get_selected_flight()
|
selected_flight = self._get_selected_flight()
|
||||||
if selected_flight is not None:
|
if selected_flight is None:
|
||||||
self._ip_zones = IpZonesJs.for_flight(selected_flight, self.game)
|
self._ip_zones = IpZonesJs.empty()
|
||||||
|
self._join_zones = JoinZonesJs.empty()
|
||||||
else:
|
else:
|
||||||
self._ip_zones = IpZonesJs([], [], [], [])
|
self._ip_zones = IpZonesJs.for_flight(selected_flight, self.game)
|
||||||
|
self._join_zones = JoinZonesJs.for_flight(selected_flight, self.game)
|
||||||
self.ipZonesChanged.emit()
|
self.ipZonesChanged.emit()
|
||||||
|
self.joinZonesChanged.emit()
|
||||||
|
|
||||||
@Property(list, notify=flightsChanged)
|
@Property(list, notify=flightsChanged)
|
||||||
def flights(self) -> List[FlightJs]:
|
def flights(self) -> List[FlightJs]:
|
||||||
@ -1121,6 +1204,10 @@ class MapModel(QObject):
|
|||||||
def ipZones(self) -> IpZonesJs:
|
def ipZones(self) -> IpZonesJs:
|
||||||
return self._ip_zones
|
return self._ip_zones
|
||||||
|
|
||||||
|
@Property(JoinZonesJs, notify=joinZonesChanged)
|
||||||
|
def joinZones(self) -> JoinZonesJs:
|
||||||
|
return self._join_zones
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def game(self) -> Game:
|
def game(self) -> Game:
|
||||||
if self.game_model.game is None:
|
if self.game_model.game is None:
|
||||||
|
|||||||
@ -198,10 +198,8 @@ const exclusionZones = L.layerGroup();
|
|||||||
const seaZones = L.layerGroup();
|
const seaZones = L.layerGroup();
|
||||||
const unculledZones = L.layerGroup();
|
const unculledZones = L.layerGroup();
|
||||||
|
|
||||||
const homeBubble = L.layerGroup();
|
const ipZones = L.layerGroup();
|
||||||
const ipBubble = L.layerGroup();
|
const joinZones = L.layerGroup().addTo(map);
|
||||||
const permissibleZone = L.layerGroup();
|
|
||||||
const safeZone = L.layerGroup();
|
|
||||||
|
|
||||||
const debugControlGroups = {
|
const debugControlGroups = {
|
||||||
"Blue Threat Zones": {
|
"Blue Threat Zones": {
|
||||||
@ -232,11 +230,9 @@ const debugControlGroups = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (ENABLE_EXPENSIVE_DEBUG_TOOLS) {
|
if (ENABLE_EXPENSIVE_DEBUG_TOOLS) {
|
||||||
debugControlGroups["IP Zones"] = {
|
debugControlGroups["Waypoint Zones"] = {
|
||||||
"Home bubble": homeBubble,
|
"IP Zones": ipZones,
|
||||||
"IP bubble": ipBubble,
|
"Join Zones": joinZones,
|
||||||
"Permissible zone": permissibleZone,
|
|
||||||
"Safe zone": safeZone,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +283,12 @@ L.control
|
|||||||
L.control
|
L.control
|
||||||
.groupedLayers(null, debugControlGroups, {
|
.groupedLayers(null, debugControlGroups, {
|
||||||
position: "topleft",
|
position: "topleft",
|
||||||
exclusiveGroups: ["Blue Threat Zones", "Red Threat Zones", "Navmeshes"],
|
exclusiveGroups: [
|
||||||
|
"Blue Threat Zones",
|
||||||
|
"Red Threat Zones",
|
||||||
|
"Navmeshes",
|
||||||
|
"Waypoint Zones",
|
||||||
|
],
|
||||||
groupCheckboxes: true,
|
groupCheckboxes: true,
|
||||||
})
|
})
|
||||||
.addTo(map);
|
.addTo(map);
|
||||||
@ -308,6 +309,7 @@ new QWebChannel(qt.webChannelTransport, function (channel) {
|
|||||||
game.mapZonesChanged.connect(drawMapZones);
|
game.mapZonesChanged.connect(drawMapZones);
|
||||||
game.unculledZonesChanged.connect(drawUnculledZones);
|
game.unculledZonesChanged.connect(drawUnculledZones);
|
||||||
game.ipZonesChanged.connect(drawIpZones);
|
game.ipZonesChanged.connect(drawIpZones);
|
||||||
|
game.joinZonesChanged.connect(drawJoinZones);
|
||||||
});
|
});
|
||||||
|
|
||||||
function recenterMap(center) {
|
function recenterMap(center) {
|
||||||
@ -992,34 +994,65 @@ function drawUnculledZones() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function drawIpZones() {
|
function drawIpZones() {
|
||||||
homeBubble.clearLayers();
|
ipZones.clearLayers();
|
||||||
ipBubble.clearLayers();
|
|
||||||
permissibleZone.clearLayers();
|
|
||||||
safeZone.clearLayers();
|
|
||||||
|
|
||||||
L.polygon(game.ipZones.homeBubble, {
|
L.polygon(game.ipZones.homeBubble, {
|
||||||
color: Colors.Highlight,
|
color: Colors.Highlight,
|
||||||
fillOpacity: 0.1,
|
fillOpacity: 0.1,
|
||||||
interactive: false,
|
interactive: false,
|
||||||
}).addTo(homeBubble);
|
}).addTo(ipZones);
|
||||||
|
|
||||||
L.polygon(game.ipZones.ipBubble, {
|
L.polygon(game.ipZones.ipBubble, {
|
||||||
color: "#bb89ff",
|
color: "#bb89ff",
|
||||||
fillOpacity: 0.1,
|
fillOpacity: 0.1,
|
||||||
interactive: false,
|
interactive: false,
|
||||||
}).addTo(ipBubble);
|
}).addTo(ipZones);
|
||||||
|
|
||||||
L.polygon(game.ipZones.permissibleZone, {
|
L.polygon(game.ipZones.permissibleZone, {
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
fillOpacity: 0.1,
|
fillOpacity: 0.1,
|
||||||
interactive: false,
|
interactive: false,
|
||||||
}).addTo(permissibleZone);
|
}).addTo(ipZones);
|
||||||
|
|
||||||
L.polygon(game.ipZones.safeZone, {
|
L.polygon(game.ipZones.safeZone, {
|
||||||
color: Colors.Green,
|
color: Colors.Green,
|
||||||
fillOpacity: 0.1,
|
fillOpacity: 0.1,
|
||||||
interactive: false,
|
interactive: false,
|
||||||
}).addTo(safeZone);
|
}).addTo(ipZones);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawJoinZones() {
|
||||||
|
joinZones.clearLayers();
|
||||||
|
|
||||||
|
L.polygon(game.joinZones.homeBubble, {
|
||||||
|
color: Colors.Highlight,
|
||||||
|
fillOpacity: 0.1,
|
||||||
|
interactive: false,
|
||||||
|
}).addTo(joinZones);
|
||||||
|
|
||||||
|
L.polygon(game.joinZones.targetBubble, {
|
||||||
|
color: "#bb89ff",
|
||||||
|
fillOpacity: 0.1,
|
||||||
|
interactive: false,
|
||||||
|
}).addTo(joinZones);
|
||||||
|
|
||||||
|
L.polygon(game.joinZones.ipBubble, {
|
||||||
|
color: "#ffffff",
|
||||||
|
fillOpacity: 0.1,
|
||||||
|
interactive: false,
|
||||||
|
}).addTo(joinZones);
|
||||||
|
|
||||||
|
L.polygon(game.joinZones.excludedZone, {
|
||||||
|
color: "#ffa500",
|
||||||
|
fillOpacity: 0.2,
|
||||||
|
stroke: false,
|
||||||
|
interactive: false,
|
||||||
|
}).addTo(joinZones);
|
||||||
|
|
||||||
|
L.polyline(game.joinZones.permissibleLine, {
|
||||||
|
color: Colors.Green,
|
||||||
|
interactive: false,
|
||||||
|
}).addTo(joinZones);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawInitialMap() {
|
function drawInitialMap() {
|
||||||
@ -1034,6 +1067,7 @@ function drawInitialMap() {
|
|||||||
drawMapZones();
|
drawMapZones();
|
||||||
drawUnculledZones();
|
drawUnculledZones();
|
||||||
drawIpZones();
|
drawIpZones();
|
||||||
|
drawJoinZones();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearAllLayers() {
|
function clearAllLayers() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user