Корректное отображение витков
This commit is contained in:
@@ -3,10 +3,8 @@
|
|||||||
pcp:
|
pcp:
|
||||||
infra:
|
infra:
|
||||||
postgres:
|
postgres:
|
||||||
# host: ${PCP_POSTGRES_HOST:localhost}
|
host: ${PCP_POSTGRES_HOST:localhost}
|
||||||
# port: ${PCP_POSTGRES_PORT:5432}
|
port: ${PCP_POSTGRES_PORT:5432}
|
||||||
host: ${PCP_POSTGRES_HOST:192.168.100.160}
|
|
||||||
port: ${PCP_POSTGRES_PORT:35400}
|
|
||||||
kafka:
|
kafka:
|
||||||
host: ${PCP_KAFKA_HOST:localhost}
|
host: ${PCP_KAFKA_HOST:localhost}
|
||||||
port: ${PCP_KAFKA_PORT:29092}
|
port: ${PCP_KAFKA_PORT:29092}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ spring:
|
|||||||
camunda:
|
camunda:
|
||||||
client:
|
client:
|
||||||
mode: self-managed
|
mode: self-managed
|
||||||
grpc-address: ${CAMUNDA_GRPC_ADDRESS:http://192.168.60.201:26500}
|
grpc-address: ${CAMUNDA_GRPC_ADDRESS:http://localhost:26500}
|
||||||
auth:
|
auth:
|
||||||
method: none
|
method: none
|
||||||
prefer-rest-over-grpc: false
|
prefer-rest-over-grpc: false
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ server:
|
|||||||
|
|
||||||
camunda:
|
camunda:
|
||||||
client:
|
client:
|
||||||
grpc-address: ${CAMUNDA_GRPC_ADDRESS:http://192.168.60.201:26500}
|
grpc-address: ${CAMUNDA_GRPC_ADDRESS:http://localhost:26500}
|
||||||
|
|
||||||
---
|
---
|
||||||
spring:
|
spring:
|
||||||
|
|||||||
@@ -296,16 +296,25 @@ export function Tgu2DMapView({
|
|||||||
>
|
>
|
||||||
<canvas className="tgu-2d-map__canvas" ref={canvasRef} />
|
<canvas className="tgu-2d-map__canvas" ref={canvasRef} />
|
||||||
<svg className="tgu-2d-map__overlay" width={size.width} height={size.height} aria-hidden="true">
|
<svg className="tgu-2d-map__overlay" width={size.width} height={size.height} aria-hidden="true">
|
||||||
{overlayPolygons.map((polygon) => (
|
{overlayPolygons.flatMap((polygon) => {
|
||||||
|
const raw = polygon.points.map((point) => projection.project(point));
|
||||||
|
const pts = unwrapX(raw, projection.worldSize);
|
||||||
|
const cls = polygon.id === selectedPolygon?.id ? "is-selected" : "is-hovered";
|
||||||
|
return ([0, projection.worldSize, -projection.worldSize] as const).flatMap((dx) => {
|
||||||
|
const visible = pts.some((p) => {
|
||||||
|
const x = p.x + dx;
|
||||||
|
return x >= -64 && x <= size.width + 64 && p.y >= -64 && p.y <= size.height + 64;
|
||||||
|
});
|
||||||
|
if (!visible) return [];
|
||||||
|
return (
|
||||||
<polygon
|
<polygon
|
||||||
key={polygon.id}
|
key={`${polygon.id}:${dx}`}
|
||||||
points={polygon.points.map((point) => {
|
points={pts.map((p) => `${p.x + dx},${p.y}`).join(" ")}
|
||||||
const screen = projection.project(point);
|
className={cls}
|
||||||
return `${screen.x},${screen.y}`;
|
|
||||||
}).join(" ")}
|
|
||||||
className={polygon.id === selectedPolygon?.id ? "is-selected" : "is-hovered"}
|
|
||||||
/>
|
/>
|
||||||
))}
|
);
|
||||||
|
});
|
||||||
|
})}
|
||||||
{targets.map((t) => {
|
{targets.map((t) => {
|
||||||
const screen = projection.project(t);
|
const screen = projection.project(t);
|
||||||
const isSelected = t.id === selectedTargetId;
|
const isSelected = t.id === selectedTargetId;
|
||||||
@@ -365,6 +374,20 @@ function layerTitle(layer: MapPolygon["layer"]): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function unwrapX(points: { x: number; y: number }[], worldSize: number): { x: number; y: number }[] {
|
||||||
|
if (points.length === 0) return [];
|
||||||
|
const out: { x: number; y: number }[] = [points[0]];
|
||||||
|
let prevX = points[0].x;
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
let x = points[i].x;
|
||||||
|
while (x - prevX > worldSize / 2) x -= worldSize;
|
||||||
|
while (prevX - x > worldSize / 2) x += worldSize;
|
||||||
|
out.push({ x, y: points[i].y });
|
||||||
|
prevX = x;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
function uniquePolygons(polygons: Array<MapPolygon | undefined>): MapPolygon[] {
|
function uniquePolygons(polygons: Array<MapPolygon | undefined>): MapPolygon[] {
|
||||||
const result: MapPolygon[] = [];
|
const result: MapPolygon[] = [];
|
||||||
const ids = new Set<string>();
|
const ids = new Set<string>();
|
||||||
|
|||||||
@@ -24,10 +24,21 @@ export function hitTestPolygons(index: PolygonSpatialIndex, point: GeoPoint): Ma
|
|||||||
let selected: MapPolygon | undefined;
|
let selected: MapPolygon | undefined;
|
||||||
|
|
||||||
for (const entry of index.entries) {
|
for (const entry of index.entries) {
|
||||||
if (!bboxContainsPoint(entry.bbox, point)) continue;
|
// Check bbox allowing ±360° shifts so antimeridian-crossing polygons are not skipped.
|
||||||
if (!pointInPolygon(point, entry.polygon.points)) continue;
|
const inBbox =
|
||||||
|
bboxContainsPoint(entry.bbox, point) ||
|
||||||
|
bboxContainsPoint(entry.bbox, { lon: point.lon + 360, lat: point.lat }) ||
|
||||||
|
bboxContainsPoint(entry.bbox, { lon: point.lon - 360, lat: point.lat });
|
||||||
|
if (!inBbox) continue;
|
||||||
|
|
||||||
if (!selected || entry.polygon.zIndex >= selected.zIndex) {
|
// Normalize polygon lons to be continuous (same idea as unwrapX for screen coords).
|
||||||
|
const normalized = unwrapLon(entry.polygon.points);
|
||||||
|
const hit =
|
||||||
|
pointInPolygon(point, normalized) ||
|
||||||
|
pointInPolygon({ lon: point.lon + 360, lat: point.lat }, normalized) ||
|
||||||
|
pointInPolygon({ lon: point.lon - 360, lat: point.lat }, normalized);
|
||||||
|
|
||||||
|
if (hit && (!selected || entry.polygon.zIndex >= selected.zIndex)) {
|
||||||
selected = entry.polygon;
|
selected = entry.polygon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,3 +53,17 @@ export function queryPolygonsByBBox(index: PolygonSpatialIndex, bbox: BBox): Map
|
|||||||
.map((entry) => entry.polygon);
|
.map((entry) => entry.polygon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function unwrapLon(points: GeoPoint[]): GeoPoint[] {
|
||||||
|
if (points.length === 0) return points;
|
||||||
|
const out: GeoPoint[] = [points[0]];
|
||||||
|
let prevLon = points[0].lon;
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
let lon = points[i].lon;
|
||||||
|
while (lon - prevLon > 180) lon -= 360;
|
||||||
|
while (prevLon - lon > 180) lon += 360;
|
||||||
|
out.push({ ...points[i], lon });
|
||||||
|
prevLon = lon;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import react from "@vitejs/plugin-react";
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
|
host: "0.0.0.0",
|
||||||
port: 5174,
|
port: 5174,
|
||||||
proxy: {
|
proxy: {
|
||||||
"/api/pcp-request": {
|
"/api/pcp-request": {
|
||||||
|
|||||||
Reference in New Issue
Block a user