@eyeon/map 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +27 -0
  2. package/dist/assets/MapViewer.css +1 -0
  3. package/dist/assets/index.css +1 -0
  4. package/dist/chunks/MapViewer.js +530 -0
  5. package/dist/chunks/MapViewer.js.map +1 -0
  6. package/dist/chunks/graph-tools.js +153 -0
  7. package/dist/chunks/graph-tools.js.map +1 -0
  8. package/dist/chunks/pathfinding.js +343 -0
  9. package/dist/chunks/pathfinding.js.map +1 -0
  10. package/dist/core/geometry/index.d.ts +42 -0
  11. package/dist/core/geometry/index.d.ts.map +1 -0
  12. package/dist/core/import/index.d.ts +51 -0
  13. package/dist/core/import/index.d.ts.map +1 -0
  14. package/dist/core/index.d.ts +7 -0
  15. package/dist/core/index.d.ts.map +1 -0
  16. package/dist/core/index.js +282 -0
  17. package/dist/core/index.js.map +1 -0
  18. package/dist/core/publish/index.d.ts +28 -0
  19. package/dist/core/publish/index.d.ts.map +1 -0
  20. package/dist/core/routing/graph-tools.d.ts +47 -0
  21. package/dist/core/routing/graph-tools.d.ts.map +1 -0
  22. package/dist/core/routing/pathfinding.d.ts +22 -0
  23. package/dist/core/routing/pathfinding.d.ts.map +1 -0
  24. package/dist/core/types.d.ts +406 -0
  25. package/dist/core/types.d.ts.map +1 -0
  26. package/dist/editor/MapEditor.d.ts +31 -0
  27. package/dist/editor/MapEditor.d.ts.map +1 -0
  28. package/dist/editor/canvas/EditorCanvas.d.ts +22 -0
  29. package/dist/editor/canvas/EditorCanvas.d.ts.map +1 -0
  30. package/dist/editor/index.css +248 -0
  31. package/dist/editor/index.d.ts +5 -0
  32. package/dist/editor/index.d.ts.map +1 -0
  33. package/dist/editor/index.js +734 -0
  34. package/dist/editor/index.js.map +1 -0
  35. package/dist/editor/panels/Inspector.d.ts +14 -0
  36. package/dist/editor/panels/Inspector.d.ts.map +1 -0
  37. package/dist/editor/panels/LeftRail.d.ts +36 -0
  38. package/dist/editor/panels/LeftRail.d.ts.map +1 -0
  39. package/dist/editor/panels/PreviewOverlay.d.ts +6 -0
  40. package/dist/editor/panels/PreviewOverlay.d.ts.map +1 -0
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/viewer/MapViewer.d.ts +26 -0
  44. package/dist/viewer/MapViewer.d.ts.map +1 -0
  45. package/dist/viewer/components/LevelMeshes.d.ts +11 -0
  46. package/dist/viewer/components/LevelMeshes.d.ts.map +1 -0
  47. package/dist/viewer/components/MapScene.d.ts +12 -0
  48. package/dist/viewer/components/MapScene.d.ts.map +1 -0
  49. package/dist/viewer/components/RouteLine.d.ts +8 -0
  50. package/dist/viewer/components/RouteLine.d.ts.map +1 -0
  51. package/dist/viewer/index.css +210 -0
  52. package/dist/viewer/index.d.ts +4 -0
  53. package/dist/viewer/index.d.ts.map +1 -0
  54. package/dist/viewer/index.js +7 -0
  55. package/dist/viewer/index.js.map +1 -0
  56. package/dist/viewer/ui/RuntimeChrome.d.ts +19 -0
  57. package/dist/viewer/ui/RuntimeChrome.d.ts.map +1 -0
  58. package/package.json +81 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathfinding.js","sources":["../../src/core/types.ts","../../src/core/geometry/index.ts","../../src/core/routing/pathfinding.ts"],"sourcesContent":["/**\n * @eyeon/map/core — shared document model types.\n * Pure TypeScript; no React / Three.js.\n */\n\nexport type MapVersion = 1 | 2;\n\nexport type LevelKind = 'outdoor' | 'floor';\n\nexport type ShapeKind =\n | 'unit'\n | 'amenity'\n | 'kiosk_screen'\n | 'connector'\n | 'entrance'\n | 'walkable'\n | 'void'\n | 'wall'\n | 'boundary'\n | 'floorplate'\n | 'decor'\n | 'label'\n | 'zone'\n | 'parking_zone'\n | 'green_area'\n | 'water'\n | 'parking_icon';\n\nexport type AnchorKind = 'unit' | 'junction' | 'connector' | 'entrance';\n\nexport type EdgeKind = 'walk' | 'unit_link' | 'connector' | 'entrance_link';\n\nexport type ConnectorKind =\n | 'escalator'\n | 'elevator'\n | 'stairs'\n | 'ramp'\n | 'travelator';\n\nexport type ConnectorDirection = 'up' | 'down' | 'both';\n\nexport type UnitStatus =\n | 'occupied'\n | 'vacant'\n | 'coming_soon'\n | 'under_renovation';\n\nexport type AssignmentTargetType =\n | 'retailer'\n | 'amenity'\n | 'kiosk'\n | 'none';\n\nexport type ShapeOrigin = 'import' | 'manual';\n\nexport type DeviceType = 'display_app' | 'desktop' | 'tablet' | 'mobile';\n\nexport type MapRenderMode = '2D' | '3D';\n\nexport interface Vec2 {\n x: number;\n y: number;\n}\n\nexport interface Vec3 {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface BBox {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n}\n\nexport interface ViewBox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** Absolute SVG path subpath preserving Illustrator beziers. */\nexport interface PathSubpath {\n d: string;\n closed: boolean;\n}\n\nexport interface ShapeGeometry {\n /** Absolute path data (Illustrator-compatible). */\n paths: PathSubpath[];\n /** Cached polygon approximation for hit-testing / routing. */\n polygons: Vec2[][];\n}\n\nexport interface ShapeStyle {\n fill?: string;\n stroke?: string;\n strokeWidth?: number;\n opacity?: number;\n extrudeHeight?: number;\n transparent?: boolean;\n}\n\nexport interface ShapeLabel {\n text?: string;\n imageKey?: string;\n size?: number;\n rotate?: number;\n offsetX?: number;\n offsetY?: number;\n color?: string;\n autoFit?: boolean;\n}\n\nexport interface LevelTransform {\n translateX: number;\n translateY: number;\n scale: number;\n rotate: number;\n}\n\nexport interface ThemeDefaults {\n MAP_STYLE: MapRenderMode;\n MAP_BACKGROUND_COLOR: string;\n ACCENT_COLOR: string;\n STORE_DEFAULT_COLOR: string;\n STORE_TEXT_COLOR: string;\n STORE_HEIGHT: number;\n WALL_COLOR: string;\n WALL_THICKNESS: number;\n BOUNDARY_COLOR: string;\n BOUNDARY_THICKNESS: number;\n BASE_COLOR: string;\n OVERLAY_COLOR: string;\n OVERLAY_OPACITY: number;\n PARKING_ZONE_COLOR: string;\n GREEN_AREA_COLOR: string;\n WATER_COLOR: string;\n WALKABLE_COLOR: string;\n KIOSK_SIZE: number;\n ZOOM_STEP: number;\n CAMERA_MAX_DISTANCE: number;\n CAMERA_MIN_DISTANCE: number;\n}\n\nexport const DEFAULT_THEME: ThemeDefaults = {\n MAP_STYLE: '2D',\n MAP_BACKGROUND_COLOR: '#f5f5f5',\n ACCENT_COLOR: '#2563eb',\n STORE_DEFAULT_COLOR: '#e2e8f0',\n STORE_TEXT_COLOR: '#1e293b',\n STORE_HEIGHT: 4,\n WALL_COLOR: '#64748b',\n WALL_THICKNESS: 0.4,\n BOUNDARY_COLOR: '#334155',\n BOUNDARY_THICKNESS: 0.6,\n BASE_COLOR: '#ffffff',\n OVERLAY_COLOR: '#000000',\n OVERLAY_OPACITY: 0.15,\n PARKING_ZONE_COLOR: '#cbd5e1',\n GREEN_AREA_COLOR: '#86efac',\n WATER_COLOR: '#7dd3fc',\n WALKABLE_COLOR: '#f8fafc',\n KIOSK_SIZE: 12,\n ZOOM_STEP: 0.5,\n CAMERA_MAX_DISTANCE: 2000,\n CAMERA_MIN_DISTANCE: 50,\n};\n\nexport interface CmMap {\n id: number;\n centerId: number;\n baseSvgKey: string | null;\n baseViewbox: ViewBox | null;\n unitsPerMeter: number;\n theme: Partial<ThemeDefaults>;\n publishedRevisionId: number | null;\n draftUpdatedAt: string | null;\n createdAt: string;\n}\n\nexport interface CmBuilding {\n id: number;\n mapId: number;\n name: string;\n ordering: number;\n}\n\nexport interface CmLevel {\n id: number;\n mapId: number;\n buildingId: number | null;\n kind: LevelKind;\n name: string;\n levelIndex: number;\n ordering: number;\n sourceSvgKey: string | null;\n sourceViewbox: ViewBox | null;\n transform: LevelTransform;\n isActive: boolean;\n}\n\nexport interface CmShape {\n id: number;\n levelId: number;\n key: string;\n kind: ShapeKind;\n geometry: ShapeGeometry;\n bbox: BBox;\n zIndex: number;\n style: ShapeStyle;\n label: ShapeLabel;\n sourceSvgId: string | null;\n origin: ShapeOrigin;\n}\n\nexport interface CmShapeAssignment {\n shapeId: number;\n targetType: AssignmentTargetType;\n retailerId: number | null;\n amenityId: number | null;\n kioskId: number | null;\n unitStatus: UnitStatus;\n unitNumber: string | null;\n customLabel: string | null;\n customImageKey: string | null;\n}\n\nexport interface CmAnchor {\n id: number;\n levelId: number;\n shapeId: number | null;\n kind: AnchorKind;\n x: number;\n y: number;\n connectorId: number | null;\n}\n\nexport interface CmRouteEdge {\n id: number;\n mapId: number;\n fromAnchorId: number;\n toAnchorId: number;\n weight: number | null;\n directed: boolean;\n accessible: boolean;\n kind: EdgeKind;\n}\n\nexport interface CmConnector {\n id: number;\n mapId: number;\n kind: ConnectorKind;\n name: string;\n direction: ConnectorDirection;\n accessible: boolean;\n}\n\nexport interface CmAmenityCatalogItem {\n id: number;\n centerId: number | null;\n code: string;\n name: string;\n iconKey: string | null;\n builtinIcon: string | null;\n ordering: number;\n isActive: boolean;\n}\n\nexport interface CmResponsiveOverride {\n id: number;\n mapId: number;\n levelId: number | null;\n device: DeviceType;\n camera: Vec3;\n controls: Vec3;\n}\n\nexport interface PublishedGraphNode {\n id: number;\n levelId: number;\n x: number;\n y: number;\n kind: AnchorKind;\n shapeId: number | null;\n connectorId: number | null;\n}\n\nexport interface PublishedGraphEdge {\n id: number;\n from: number;\n to: number;\n weight: number;\n directed: boolean;\n accessible: boolean;\n kind: EdgeKind;\n}\n\nexport interface PublishedLevel {\n id: number;\n buildingId: number | null;\n kind: LevelKind;\n name: string;\n levelIndex: number;\n ordering: number;\n sourceSvgUrl: string | null;\n viewbox: ViewBox | null;\n transform: LevelTransform;\n shapes: Array<CmShape & { assignment?: CmShapeAssignment | null }>;\n anchors: CmAnchor[];\n}\n\nexport interface PublishedDocument {\n version: 2;\n revisionId: number;\n revisionNumber: number;\n centerId: number;\n mapId: number;\n theme: ThemeDefaults;\n baseSvgUrl: string | null;\n baseViewbox: ViewBox | null;\n buildings: CmBuilding[];\n levels: PublishedLevel[];\n connectors: CmConnector[];\n amenities: CmAmenityCatalogItem[];\n graph: {\n nodes: PublishedGraphNode[];\n edges: PublishedGraphEdge[];\n };\n responsiveOverrides: CmResponsiveOverride[];\n publishedAt: string;\n}\n\nexport interface ImportClassification {\n sourceSvgId: string;\n kind: ShapeKind | null;\n guessed: boolean;\n message?: string;\n}\n\nexport interface ImportReport {\n classified: ImportClassification[];\n unrecognized: string[];\n guessed: ImportClassification[];\n walkableCount: number;\n voidCount: number;\n unitCount: number;\n warnings: string[];\n}\n\nexport type DiffChangeType = 'added' | 'removed' | 'moved' | 'unchanged' | 'kind_changed';\n\nexport interface ImportDiffItem {\n sourceSvgId: string;\n change: DiffChangeType;\n existingShapeId?: number;\n newKind?: ShapeKind | null;\n existingKind?: ShapeKind | null;\n preserve?: {\n key?: string;\n assignment?: boolean;\n anchors?: boolean;\n };\n}\n\nexport interface ImportDiff {\n items: ImportDiffItem[];\n shapes: Array<{\n key: string;\n kind: ShapeKind;\n geometry: ShapeGeometry;\n bbox: BBox;\n sourceSvgId: string;\n style: ShapeStyle;\n }>;\n viewbox: ViewBox | null;\n}\n\nexport interface WeldResult {\n survivingAnchorId: number;\n removedAnchorIds: number[];\n rewiredEdgeIds: number[];\n}\n\nexport interface AutoConnectResult {\n unitAnchorId: number;\n junctionAnchor: { x: number; y: number; existingId?: number };\n edge: { fromAnchorId: number; toAnchorId?: number };\n}\n\nexport interface SkeletonSuggestion {\n anchors: Array<{ tempId: string; x: number; y: number; kind: AnchorKind }>;\n edges: Array<{ fromTempId: string; toTempId: string }>;\n}\n\nexport interface PathResult {\n anchorIds: number[];\n points: Array<Vec2 & { levelId: number }>;\n totalWeight: number;\n levelChanges: Array<{ fromLevelId: number; toLevelId: number; connectorId: number | null }>;\n}\n\nexport type BatchOp =\n | { op: 'upsert_shape'; shape: Partial<CmShape> & { levelId: number; key: string } }\n | { op: 'delete_shape'; shapeId: number }\n | { op: 'upsert_assignment'; assignment: CmShapeAssignment }\n | { op: 'delete_assignment'; shapeId: number }\n | { op: 'upsert_anchor'; anchor: Partial<CmAnchor> & { levelId: number; x: number; y: number; kind: AnchorKind } }\n | { op: 'delete_anchor'; anchorId: number }\n | { op: 'upsert_edge'; edge: Partial<CmRouteEdge> & { mapId: number; fromAnchorId: number; toAnchorId: number } }\n | { op: 'delete_edge'; edgeId: number }\n | { op: 'weld_anchors'; anchorIds: number[]; tolerance?: number }\n | { op: 'upsert_level'; level: Partial<CmLevel> & { mapId: number; name: string; kind: LevelKind } }\n | { op: 'delete_level'; levelId: number }\n | { op: 'upsert_building'; building: Partial<CmBuilding> & { mapId: number; name: string } }\n | { op: 'delete_building'; buildingId: number }\n | { op: 'update_theme'; theme: Partial<ThemeDefaults> }\n | { op: 'upsert_connector'; connector: Partial<CmConnector> & { mapId: number; kind: ConnectorKind; name: string } }\n | { op: 'delete_connector'; connectorId: number };\n\nexport const INTERACTIVE_SHAPE_KINDS: ShapeKind[] = [\n 'unit',\n 'amenity',\n 'kiosk_screen',\n 'connector',\n 'entrance',\n 'parking_zone',\n];\n\nexport const FLOOR_CHANGE_PENALTY = 10000;\n\nexport const DEFAULT_WELD_TOLERANCE = 2.5;\n","import type { BBox, PathSubpath, ShapeGeometry, Vec2, ViewBox } from '../types';\n\n/** Flip Y once at import so DB space is Y-up / consistent. */\nexport function flipY(points: Vec2[], viewboxHeight: number): Vec2[] {\n return points.map((p) => ({ x: p.x, y: viewboxHeight - p.y }));\n}\n\nexport function distance(a: Vec2, b: Vec2): number {\n const dx = a.x - b.x;\n const dy = a.y - b.y;\n return Math.hypot(dx, dy);\n}\n\nexport function bboxOf(points: Vec2[]): BBox {\n if (points.length === 0) {\n return { minX: 0, minY: 0, maxX: 0, maxY: 0 };\n }\n let minX = points[0].x;\n let minY = points[0].y;\n let maxX = points[0].x;\n let maxY = points[0].y;\n for (let i = 1; i < points.length; i++) {\n const p = points[i];\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { minX, minY, maxX, maxY };\n}\n\nexport function bboxUnion(a: BBox, b: BBox): BBox {\n return {\n minX: Math.min(a.minX, b.minX),\n minY: Math.min(a.minY, b.minY),\n maxX: Math.max(a.maxX, b.maxX),\n maxY: Math.max(a.maxY, b.maxY),\n };\n}\n\nexport function centroid(points: Vec2[]): Vec2 {\n if (points.length === 0) return { x: 0, y: 0 };\n let sx = 0;\n let sy = 0;\n for (const p of points) {\n sx += p.x;\n sy += p.y;\n }\n return { x: sx / points.length, y: sy / points.length };\n}\n\nexport function pointInPolygon(point: Vec2, polygon: Vec2[]): boolean {\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const xi = polygon[i].x;\n const yi = polygon[i].y;\n const xj = polygon[j].x;\n const yj = polygon[j].y;\n const intersect =\n yi > point.y !== yj > point.y &&\n point.x < ((xj - xi) * (point.y - yi)) / (yj - yi + Number.EPSILON) + xi;\n if (intersect) inside = !inside;\n }\n return inside;\n}\n\nexport function pointInPolygons(point: Vec2, polygons: Vec2[][]): boolean {\n return polygons.some((poly) => pointInPolygon(point, poly));\n}\n\n/** Project point onto segment; returns closest point and t in [0,1]. */\nexport function projectOntoSegment(\n point: Vec2,\n a: Vec2,\n b: Vec2,\n): { point: Vec2; t: number; distance: number } {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const lenSq = dx * dx + dy * dy;\n if (lenSq === 0) {\n return { point: { ...a }, t: 0, distance: distance(point, a) };\n }\n let t = ((point.x - a.x) * dx + (point.y - a.y) * dy) / lenSq;\n t = Math.max(0, Math.min(1, t));\n const proj = { x: a.x + t * dx, y: a.y + t * dy };\n return { point: proj, t, distance: distance(point, proj) };\n}\n\nexport function nearestPointOnPolyline(\n point: Vec2,\n polyline: Vec2[],\n): { point: Vec2; segmentIndex: number; distance: number } | null {\n if (polyline.length < 2) return null;\n let best: { point: Vec2; segmentIndex: number; distance: number } | null = null;\n for (let i = 0; i < polyline.length - 1; i++) {\n const proj = projectOntoSegment(point, polyline[i], polyline[i + 1]);\n if (!best || proj.distance < best.distance) {\n best = { point: proj.point, segmentIndex: i, distance: proj.distance };\n }\n }\n return best;\n}\n\n/**\n * Approximate a cubic bezier into line segments.\n */\nexport function approximateCubic(\n p0: Vec2,\n p1: Vec2,\n p2: Vec2,\n p3: Vec2,\n segments = 8,\n): Vec2[] {\n const out: Vec2[] = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const u = 1 - t;\n out.push({\n x:\n u * u * u * p0.x +\n 3 * u * u * t * p1.x +\n 3 * u * t * t * p2.x +\n t * t * t * p3.x,\n y:\n u * u * u * p0.y +\n 3 * u * u * t * p1.y +\n 3 * u * t * t * p2.y +\n t * t * t * p3.y,\n });\n }\n return out;\n}\n\nexport function approximateQuadratic(\n p0: Vec2,\n p1: Vec2,\n p2: Vec2,\n segments = 6,\n): Vec2[] {\n const out: Vec2[] = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const u = 1 - t;\n out.push({\n x: u * u * p0.x + 2 * u * t * p1.x + t * t * p2.x,\n y: u * u * p0.y + 2 * u * t * p1.y + t * t * p2.y,\n });\n }\n return out;\n}\n\n/**\n * Parse SVG path `d` into absolute polygon approximations.\n * Supports M/L/H/V/C/Q/S/T/Z (absolute and relative).\n */\nexport function pathToPolygons(d: string, flipYHeight?: number): Vec2[][] {\n const tokens = d.match(/[a-zA-Z]|-?\\d*\\.?\\d+(?:e[-+]?\\d+)?/g) ?? [];\n const polygons: Vec2[][] = [];\n let current: Vec2[] = [];\n let x = 0;\n let y = 0;\n let startX = 0;\n let startY = 0;\n let lastCtrl: Vec2 | null = null;\n let i = 0;\n let cmd = '';\n\n const readNum = () => Number(tokens[i++]);\n\n while (i < tokens.length) {\n const t = tokens[i];\n if (/[a-zA-Z]/.test(t)) {\n cmd = t;\n i++;\n }\n\n switch (cmd) {\n case 'M':\n case 'm': {\n const isRel = cmd === 'm';\n const nx = readNum();\n const ny = readNum();\n x = isRel ? x + nx : nx;\n y = isRel ? y + ny : ny;\n if (current.length > 0) polygons.push(current);\n current = [{ x, y }];\n startX = x;\n startY = y;\n lastCtrl = null;\n cmd = isRel ? 'l' : 'L';\n break;\n }\n case 'L':\n case 'l': {\n const isRel = cmd === 'l';\n const nx = readNum();\n const ny = readNum();\n x = isRel ? x + nx : nx;\n y = isRel ? y + ny : ny;\n current.push({ x, y });\n lastCtrl = null;\n break;\n }\n case 'H':\n case 'h': {\n const isRel = cmd === 'h';\n const nx = readNum();\n x = isRel ? x + nx : nx;\n current.push({ x, y });\n lastCtrl = null;\n break;\n }\n case 'V':\n case 'v': {\n const isRel = cmd === 'v';\n const ny = readNum();\n y = isRel ? y + ny : ny;\n current.push({ x, y });\n lastCtrl = null;\n break;\n }\n case 'C':\n case 'c': {\n const isRel = cmd === 'c';\n const x1 = isRel ? x + readNum() : readNum();\n const y1 = isRel ? y + readNum() : readNum();\n const x2 = isRel ? x + readNum() : readNum();\n const y2 = isRel ? y + readNum() : readNum();\n const nx = isRel ? x + readNum() : readNum();\n const ny = isRel ? y + readNum() : readNum();\n const approx = approximateCubic(\n { x, y },\n { x: x1, y: y1 },\n { x: x2, y: y2 },\n { x: nx, y: ny },\n );\n current.push(...approx.slice(1));\n lastCtrl = { x: x2, y: y2 };\n x = nx;\n y = ny;\n break;\n }\n case 'Q':\n case 'q': {\n const isRel = cmd === 'q';\n const x1 = isRel ? x + readNum() : readNum();\n const y1 = isRel ? y + readNum() : readNum();\n const nx = isRel ? x + readNum() : readNum();\n const ny = isRel ? y + readNum() : readNum();\n const approx = approximateQuadratic(\n { x, y },\n { x: x1, y: y1 },\n { x: nx, y: ny },\n );\n current.push(...approx.slice(1));\n lastCtrl = { x: x1, y: y1 };\n x = nx;\n y = ny;\n break;\n }\n case 'S':\n case 's': {\n const isRel = cmd === 's';\n const cx: number = lastCtrl ? 2 * x - lastCtrl.x : x;\n const cy: number = lastCtrl ? 2 * y - lastCtrl.y : y;\n const x2 = isRel ? x + readNum() : readNum();\n const y2 = isRel ? y + readNum() : readNum();\n const nx = isRel ? x + readNum() : readNum();\n const ny = isRel ? y + readNum() : readNum();\n const approx = approximateCubic(\n { x, y },\n { x: cx, y: cy },\n { x: x2, y: y2 },\n { x: nx, y: ny },\n );\n current.push(...approx.slice(1));\n lastCtrl = { x: x2, y: y2 };\n x = nx;\n y = ny;\n break;\n }\n case 'T':\n case 't': {\n const isRel = cmd === 't';\n const cx: number = lastCtrl ? 2 * x - lastCtrl.x : x;\n const cy: number = lastCtrl ? 2 * y - lastCtrl.y : y;\n const nx = isRel ? x + readNum() : readNum();\n const ny = isRel ? y + readNum() : readNum();\n const approx = approximateQuadratic(\n { x, y },\n { x: cx, y: cy },\n { x: nx, y: ny },\n );\n current.push(...approx.slice(1));\n lastCtrl = { x: cx, y: cy };\n x = nx;\n y = ny;\n break;\n }\n case 'Z':\n case 'z': {\n current.push({ x: startX, y: startY });\n polygons.push(current);\n current = [];\n x = startX;\n y = startY;\n lastCtrl = null;\n break;\n }\n default:\n // Unknown command — skip one token to avoid infinite loop\n i++;\n break;\n }\n }\n\n if (current.length > 0) polygons.push(current);\n\n if (flipYHeight != null) {\n return polygons.map((poly) => flipY(poly, flipYHeight));\n }\n return polygons;\n}\n\nexport function buildGeometryFromPaths(\n pathDs: string[],\n viewbox: ViewBox | null,\n normalizeY = true,\n): ShapeGeometry {\n const height = viewbox?.height ?? 0;\n const paths: PathSubpath[] = pathDs.map((d) => ({\n d,\n closed: /z/i.test(d),\n }));\n const polygons = pathDs.flatMap((d) =>\n pathToPolygons(d, normalizeY && height > 0 ? height : undefined),\n );\n return { paths, polygons };\n}\n\nexport function geometryBBox(geometry: ShapeGeometry): BBox {\n const all = geometry.polygons.flat();\n return bboxOf(all);\n}\n\nexport function geometryCentroid(geometry: ShapeGeometry): Vec2 {\n return centroid(geometry.polygons.flat());\n}\n\n/**\n * Snap a delta angle to the nearest increment around a base angle.\n * baseDeg is the working orientation (e.g. from \"match this wall\").\n */\nexport function snapAngle(\n from: Vec2,\n to: Vec2,\n baseDeg = 0,\n increments: number[] = [15, 45, 90],\n): Vec2 {\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n const len = Math.hypot(dx, dy);\n if (len === 0) return { ...to };\n\n const rawDeg = (Math.atan2(dy, dx) * 180) / Math.PI;\n const relative = rawDeg - baseDeg;\n let best = relative;\n let bestDiff = Infinity;\n for (const step of increments) {\n const snapped = Math.round(relative / step) * step;\n const diff = Math.abs(relative - snapped);\n if (diff < bestDiff) {\n bestDiff = diff;\n best = snapped;\n }\n }\n const finalDeg = ((best + baseDeg) * Math.PI) / 180;\n return {\n x: from.x + Math.cos(finalDeg) * len,\n y: from.y + Math.sin(finalDeg) * len,\n };\n}\n\n/** Derive working base angle from two wall points (degrees). */\nexport function angleFromWall(a: Vec2, b: Vec2): number {\n return (Math.atan2(b.y - a.y, b.x - a.x) * 180) / Math.PI;\n}\n\nexport function parseViewBox(raw: string | null | undefined): ViewBox | null {\n if (!raw) return null;\n const parts = raw.trim().split(/[\\s,]+/).map(Number);\n if (parts.length !== 4 || parts.some((n) => Number.isNaN(n))) return null;\n return { x: parts[0], y: parts[1], width: parts[2], height: parts[3] };\n}\n","import createGraph, { type Graph } from 'ngraph.graph';\nimport path from 'ngraph.path';\nimport type {\n CmAnchor,\n CmConnector,\n CmRouteEdge,\n PathResult,\n PublishedGraphEdge,\n PublishedGraphNode,\n} from '../types';\nimport { FLOOR_CHANGE_PENALTY } from '../types';\nimport { distance } from '../geometry';\n\nexport interface CompiledGraph {\n graph: Graph;\n nodes: PublishedGraphNode[];\n edges: PublishedGraphEdge[];\n anchorById: Map<number, CmAnchor>;\n}\n\nexport function compileGraph(\n anchors: CmAnchor[],\n edges: CmRouteEdge[],\n connectors: CmConnector[] = [],\n): CompiledGraph {\n const graph = createGraph();\n const anchorById = new Map(anchors.map((a) => [a.id, a]));\n const connectorById = new Map(connectors.map((c) => [c.id, c]));\n\n const nodes: PublishedGraphNode[] = anchors.map((a) => ({\n id: a.id,\n levelId: a.levelId,\n x: a.x,\n y: a.y,\n kind: a.kind,\n shapeId: a.shapeId,\n connectorId: a.connectorId,\n }));\n\n for (const n of nodes) {\n graph.addNode(n.id, n);\n }\n\n const publishedEdges: PublishedGraphEdge[] = [];\n\n for (const e of edges) {\n const from = anchorById.get(e.fromAnchorId);\n const to = anchorById.get(e.toAnchorId);\n if (!from || !to) continue;\n\n let weight = e.weight;\n if (weight == null) {\n weight = distance(from, to);\n if (from.levelId !== to.levelId) {\n weight += FLOOR_CHANGE_PENALTY;\n }\n }\n\n // Accessibility: connector edges inherit connector.accessible\n let accessible = e.accessible;\n if (e.kind === 'connector' && from.connectorId != null) {\n const conn = connectorById.get(from.connectorId);\n if (conn) accessible = conn.accessible;\n }\n\n const pub: PublishedGraphEdge = {\n id: e.id,\n from: e.fromAnchorId,\n to: e.toAnchorId,\n weight,\n directed: e.directed,\n accessible,\n kind: e.kind,\n };\n publishedEdges.push(pub);\n\n graph.addLink(e.fromAnchorId, e.toAnchorId, pub);\n if (!e.directed) {\n graph.addLink(e.toAnchorId, e.fromAnchorId, pub);\n }\n }\n\n return { graph, nodes, edges: publishedEdges, anchorById };\n}\n\nexport interface FindPathOptions {\n accessibleOnly?: boolean;\n}\n\n/**\n * NBA* pathfinding over the compiled graph.\n * Returns null if no path exists.\n */\nexport function findPath(\n compiled: CompiledGraph,\n fromAnchorId: number,\n toAnchorId: number,\n options: FindPathOptions = {},\n): PathResult | null {\n const { graph, anchorById } = compiled;\n if (!anchorById.has(fromAnchorId) || !anchorById.has(toAnchorId)) {\n return null;\n }\n\n const finder = path.nba(graph, {\n distance(fromNode, toNode, link) {\n const data = link.data as PublishedGraphEdge | undefined;\n if (options.accessibleOnly && data && !data.accessible) {\n return Number.POSITIVE_INFINITY;\n }\n return data?.weight ?? 1;\n },\n heuristic(fromNode, toNode) {\n const a = anchorById.get(fromNode.id as number);\n const b = anchorById.get(toNode.id as number);\n if (!a || !b) return 0;\n let d = distance(a, b);\n if (a.levelId !== b.levelId) d += FLOOR_CHANGE_PENALTY;\n return d;\n },\n });\n\n const raw = finder.find(fromAnchorId, toAnchorId);\n if (!raw || raw.length === 0) return null;\n\n // ngraph returns destination → start; reverse\n const nodes = raw.reverse();\n const anchorIds = nodes.map((n) => n.id as number);\n const points: PathResult['points'] = [];\n const levelChanges: PathResult['levelChanges'] = [];\n let totalWeight = 0;\n\n for (let i = 0; i < anchorIds.length; i++) {\n const a = anchorById.get(anchorIds[i])!;\n points.push({ x: a.x, y: a.y, levelId: a.levelId });\n if (i > 0) {\n const prev = anchorById.get(anchorIds[i - 1])!;\n totalWeight += distance(prev, a);\n if (prev.levelId !== a.levelId) {\n totalWeight += FLOOR_CHANGE_PENALTY;\n levelChanges.push({\n fromLevelId: prev.levelId,\n toLevelId: a.levelId,\n connectorId: a.connectorId ?? prev.connectorId,\n });\n }\n }\n }\n\n return { anchorIds, points, totalWeight, levelChanges };\n}\n\n/**\n * Find the nearest matching amenity shape anchor from a start point.\n */\nexport function findNearestAmenityPath(\n compiled: CompiledGraph,\n fromAnchorId: number,\n amenityAnchorIds: number[],\n options: FindPathOptions = {},\n): PathResult | null {\n let best: PathResult | null = null;\n for (const targetId of amenityAnchorIds) {\n const result = findPath(compiled, fromAnchorId, targetId, options);\n if (!result) continue;\n if (!best || result.totalWeight < best.totalWeight) {\n best = result;\n }\n }\n return best;\n}\n"],"names":["DEFAULT_THEME","INTERACTIVE_SHAPE_KINDS","FLOOR_CHANGE_PENALTY","DEFAULT_WELD_TOLERANCE","flipY","points","viewboxHeight","p","distance","a","b","dx","dy","bboxOf","minX","minY","maxX","maxY","i","bboxUnion","centroid","sx","sy","pointInPolygon","point","polygon","inside","j","xi","yi","xj","yj","pointInPolygons","polygons","poly","projectOntoSegment","lenSq","proj","nearestPointOnPolyline","polyline","best","approximateCubic","p0","p1","p2","p3","segments","out","t","u","approximateQuadratic","pathToPolygons","d","flipYHeight","tokens","current","x","y","startX","startY","lastCtrl","cmd","readNum","isRel","nx","ny","x1","y1","x2","y2","approx","cx","cy","buildGeometryFromPaths","pathDs","viewbox","normalizeY","height","paths","geometryBBox","geometry","all","geometryCentroid","snapAngle","from","to","baseDeg","increments","len","relative","bestDiff","step","snapped","diff","finalDeg","angleFromWall","parseViewBox","raw","parts","n","compileGraph","anchors","edges","connectors","graph","createGraph","anchorById","connectorById","nodes","publishedEdges","e","weight","accessible","conn","pub","findPath","compiled","fromAnchorId","toAnchorId","options","path","fromNode","toNode","link","data","anchorIds","levelChanges","totalWeight","prev","findNearestAmenityPath","amenityAnchorIds","targetId","result"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { BBox, ShapeGeometry, Vec2, ViewBox } from '../types';
2
+ /** Flip Y once at import so DB space is Y-up / consistent. */
3
+ export declare function flipY(points: Vec2[], viewboxHeight: number): Vec2[];
4
+ export declare function distance(a: Vec2, b: Vec2): number;
5
+ export declare function bboxOf(points: Vec2[]): BBox;
6
+ export declare function bboxUnion(a: BBox, b: BBox): BBox;
7
+ export declare function centroid(points: Vec2[]): Vec2;
8
+ export declare function pointInPolygon(point: Vec2, polygon: Vec2[]): boolean;
9
+ export declare function pointInPolygons(point: Vec2, polygons: Vec2[][]): boolean;
10
+ /** Project point onto segment; returns closest point and t in [0,1]. */
11
+ export declare function projectOntoSegment(point: Vec2, a: Vec2, b: Vec2): {
12
+ point: Vec2;
13
+ t: number;
14
+ distance: number;
15
+ };
16
+ export declare function nearestPointOnPolyline(point: Vec2, polyline: Vec2[]): {
17
+ point: Vec2;
18
+ segmentIndex: number;
19
+ distance: number;
20
+ } | null;
21
+ /**
22
+ * Approximate a cubic bezier into line segments.
23
+ */
24
+ export declare function approximateCubic(p0: Vec2, p1: Vec2, p2: Vec2, p3: Vec2, segments?: number): Vec2[];
25
+ export declare function approximateQuadratic(p0: Vec2, p1: Vec2, p2: Vec2, segments?: number): Vec2[];
26
+ /**
27
+ * Parse SVG path `d` into absolute polygon approximations.
28
+ * Supports M/L/H/V/C/Q/S/T/Z (absolute and relative).
29
+ */
30
+ export declare function pathToPolygons(d: string, flipYHeight?: number): Vec2[][];
31
+ export declare function buildGeometryFromPaths(pathDs: string[], viewbox: ViewBox | null, normalizeY?: boolean): ShapeGeometry;
32
+ export declare function geometryBBox(geometry: ShapeGeometry): BBox;
33
+ export declare function geometryCentroid(geometry: ShapeGeometry): Vec2;
34
+ /**
35
+ * Snap a delta angle to the nearest increment around a base angle.
36
+ * baseDeg is the working orientation (e.g. from "match this wall").
37
+ */
38
+ export declare function snapAngle(from: Vec2, to: Vec2, baseDeg?: number, increments?: number[]): Vec2;
39
+ /** Derive working base angle from two wall points (degrees). */
40
+ export declare function angleFromWall(a: Vec2, b: Vec2): number;
41
+ export declare function parseViewBox(raw: string | null | undefined): ViewBox | null;
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/geometry/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAe,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEhF,8DAA8D;AAC9D,wBAAgB,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,EAAE,CAEnE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAIjD;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAgB3C;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,IAAI,CAOhD;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAS7C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAapE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAExE;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,IAAI,EACX,CAAC,EAAE,IAAI,EACP,CAAC,EAAE,IAAI,GACN;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAW9C;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,IAAI,EAAE,GACf;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUhE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,IAAI,EACR,EAAE,EAAE,IAAI,EACR,EAAE,EAAE,IAAI,EACR,EAAE,EAAE,IAAI,EACR,QAAQ,SAAI,GACX,IAAI,EAAE,CAmBR;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,IAAI,EACR,EAAE,EAAE,IAAI,EACR,EAAE,EAAE,IAAI,EACR,QAAQ,SAAI,GACX,IAAI,EAAE,CAWR;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,CAuKxE;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,UAAU,UAAO,GAChB,aAAa,CAUf;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAG1D;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAE9D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,IAAI,EACR,OAAO,SAAI,EACX,UAAU,GAAE,MAAM,EAAiB,GAClC,IAAI,CAuBN;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAEtD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,GAAG,IAAI,CAK3E"}
@@ -0,0 +1,51 @@
1
+ import { BBox, ImportDiff, ImportReport, ShapeGeometry, ShapeKind, ShapeStyle, ViewBox } from '../types';
2
+ export interface RawSvgElement {
3
+ id: string;
4
+ tag: string;
5
+ d?: string;
6
+ points?: string;
7
+ x1?: number;
8
+ y1?: number;
9
+ x2?: number;
10
+ y2?: number;
11
+ interactive?: boolean;
12
+ }
13
+ export interface ParsedSvg {
14
+ viewbox: ViewBox | null;
15
+ elements: RawSvgElement[];
16
+ routePathDs: string[];
17
+ }
18
+ export declare function classifyId(id: string, mode?: 'floor' | 'base'): {
19
+ kind: ShapeKind | null;
20
+ guessed: boolean;
21
+ };
22
+ /**
23
+ * Lightweight SVG string parser — no DOM required (works in Node).
24
+ * Extracts elements with id attributes and path-like geometry.
25
+ */
26
+ export declare function parseSvgString(svg: string): ParsedSvg;
27
+ export interface ImportedShapeDraft {
28
+ key: string;
29
+ kind: ShapeKind;
30
+ geometry: ShapeGeometry;
31
+ bbox: BBox;
32
+ sourceSvgId: string;
33
+ style: ShapeStyle;
34
+ }
35
+ export declare function importSvg(svg: string, mode?: 'floor' | 'base'): {
36
+ report: ImportReport;
37
+ shapes: ImportedShapeDraft[];
38
+ viewbox: ViewBox | null;
39
+ routePathDs: string[];
40
+ };
41
+ export interface ExistingShapeRef {
42
+ id: number;
43
+ sourceSvgId: string | null;
44
+ kind: ShapeKind;
45
+ key: string;
46
+ }
47
+ /**
48
+ * Diff newly imported shapes against existing level shapes by source_svg_id.
49
+ */
50
+ export declare function diffImport(imported: ImportedShapeDraft[], existing: ExistingShapeRef[], viewbox: ViewBox | null): ImportDiff;
51
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/import/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,IAAI,EAEJ,UAAU,EAEV,YAAY,EACZ,aAAa,EACb,SAAS,EACT,UAAU,EACV,OAAO,EACR,MAAM,UAAU,CAAC;AAmDlB,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,OAAO,GAAG,MAAgB,GAC/B;IAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAa9C;AAiBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CA+ErD;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,IAAI,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;CACnB;AAUD,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,OAAO,GAAG,MAAgB,GAC/B;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,CAgFxG;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,kBAAkB,EAAE,EAC9B,QAAQ,EAAE,gBAAgB,EAAE,EAC5B,OAAO,EAAE,OAAO,GAAG,IAAI,GACtB,UAAU,CAuDZ"}
@@ -0,0 +1,7 @@
1
+ export * from './types';
2
+ export * from './geometry';
3
+ export * from './import';
4
+ export * from './routing/graph-tools';
5
+ export * from './routing/pathfinding';
6
+ export * from './publish';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,WAAW,CAAC"}
@@ -0,0 +1,282 @@
1
+ import { b as w, g as I, c as y, e as S, f as E } from "../chunks/pathfinding.js";
2
+ import { D as K, F as U, I as z, h as B, i as W, j as G, k as V, l as H, m as j, d as X, o as Z, q as Y, r as q, s as Q, n as J, a as ee, t as ne, p as ie, u as se, v as te } from "../chunks/pathfinding.js";
3
+ import { a as re, b as ae, f as ce, i as de, u as le, w as pe } from "../chunks/graph-tools.js";
4
+ const P = [
5
+ { prefix: "walkable", kind: "walkable" },
6
+ { prefix: "void", kind: "void" },
7
+ { prefix: "unit", kind: "unit" },
8
+ { prefix: "store", kind: "unit" },
9
+ // v1 compatibility
10
+ { prefix: "wall", kind: "wall" },
11
+ { prefix: "boundary", kind: "boundary" },
12
+ { prefix: "outer-wall", kind: "wall" },
13
+ { prefix: "amenity-", kind: "amenity" },
14
+ { prefix: "kiosk-", kind: "kiosk_screen" },
15
+ { prefix: "escalator-", kind: "connector" },
16
+ { prefix: "elevator-", kind: "connector" },
17
+ { prefix: "stairs-", kind: "connector" },
18
+ { prefix: "entrance-", kind: "entrance" },
19
+ { prefix: "zone-", kind: "zone" },
20
+ { prefix: "label-", kind: "label" },
21
+ { prefix: "floorplate", kind: "floorplate" },
22
+ { prefix: "base", kind: "floorplate" },
23
+ { prefix: "decor", kind: "decor" },
24
+ { prefix: "special-shape", kind: "decor" },
25
+ { prefix: "overlay", kind: "decor" }
26
+ ], $ = [
27
+ { prefix: "parking-zone", kind: "parking_zone" },
28
+ { prefix: "parking-lane", kind: "parking_zone" },
29
+ { prefix: "parking-line", kind: "decor" },
30
+ { prefix: "parking-icon", kind: "parking_icon" },
31
+ { prefix: "green-area", kind: "green_area" },
32
+ { prefix: "water", kind: "water" },
33
+ { prefix: "decor", kind: "decor" },
34
+ { prefix: "entrance-", kind: "entrance" },
35
+ { prefix: "unit", kind: "unit" },
36
+ { prefix: "store", kind: "unit" },
37
+ { prefix: "interactive-", kind: "unit" },
38
+ { prefix: "walkable", kind: "walkable" },
39
+ { prefix: "amenity-", kind: "amenity" }
40
+ ], A = "route-path";
41
+ function L(n, t = "floor") {
42
+ const o = n.toLowerCase(), a = t === "base" ? $ : P;
43
+ for (const { prefix: l, kind: p } of a)
44
+ if (o === l || o.startsWith(l))
45
+ return { kind: p, guessed: !1 };
46
+ return o.startsWith("interactive") ? { kind: "unit", guessed: !0 } : { kind: null, guessed: !1 };
47
+ }
48
+ function v(n) {
49
+ const t = n.trim().split(/[\s,]+/).map(Number);
50
+ if (t.length < 4) return "";
51
+ let o = `M ${t[0]} ${t[1]}`;
52
+ for (let a = 2; a < t.length; a += 2)
53
+ o += ` L ${t[a]} ${t[a + 1]}`;
54
+ return o += " Z", o;
55
+ }
56
+ function _(n, t, o, a) {
57
+ return `M ${n} ${t} L ${o} ${a}`;
58
+ }
59
+ function C(n) {
60
+ const t = n.match(/viewBox\s*=\s*["']([^"']+)["']/i), o = y(t == null ? void 0 : t[1]), a = [], l = [], p = /<(path|polygon|polyline|line|rect|g)\b([^>]*)(?:\/>|>([\s\S]*?)<\/\1>)/gi;
61
+ let i;
62
+ for (; (i = p.exec(n)) !== null; ) {
63
+ const e = i[1].toLowerCase(), c = i[2] ?? "", k = c.match(/\bid\s*=\s*["']([^"']+)["']/i);
64
+ if (!k) continue;
65
+ const f = k[1], g = /\bdata-interactive\s*=\s*["']?(true|1|yes)/i.test(c);
66
+ if (f.toLowerCase().startsWith(A)) {
67
+ const s = c.match(/\bd\s*=\s*["']([^"']+)["']/i);
68
+ s && l.push(s[1]);
69
+ const r = c.match(/\bpoints\s*=\s*["']([^"']+)["']/i);
70
+ r && l.push(v(r[1]).replace(/ Z$/, ""));
71
+ continue;
72
+ }
73
+ const d = { id: f, tag: e, interactive: g };
74
+ if (e === "path") {
75
+ const s = c.match(/\bd\s*=\s*["']([^"']+)["']/i);
76
+ s && (d.d = s[1]);
77
+ } else if (e === "polygon" || e === "polyline") {
78
+ const s = c.match(/\bpoints\s*=\s*["']([^"']+)["']/i);
79
+ s && (d.d = v(s[1]));
80
+ } else if (e === "line") {
81
+ const s = (r) => {
82
+ const u = c.match(new RegExp(`\\b${r}\\s*=\\s*["']?(-?[\\d.]+)`, "i"));
83
+ return u ? Number(u[1]) : 0;
84
+ };
85
+ d.d = _(s("x1"), s("y1"), s("x2"), s("y2"));
86
+ } else if (e === "rect") {
87
+ const s = (b) => {
88
+ const m = c.match(new RegExp(`\\b${b}\\s*=\\s*["']?(-?[\\d.]+)`, "i"));
89
+ return m ? Number(m[1]) : 0;
90
+ }, r = s("x"), u = s("y"), h = s("width"), x = s("height");
91
+ d.d = `M ${r} ${u} L ${r + h} ${u} L ${r + h} ${u + x} L ${r} ${u + x} Z`;
92
+ } else if (e === "g") {
93
+ const s = i[3] ?? "", r = [], u = /<(path|polygon|polyline|line|rect)\b([^>]*)\/?>/gi;
94
+ let h;
95
+ for (; (h = u.exec(s)) !== null; ) {
96
+ const x = h[1].toLowerCase(), b = h[2] ?? "";
97
+ if (x === "path") {
98
+ const m = b.match(/\bd\s*=\s*["']([^"']+)["']/i);
99
+ m && r.push(m[1]);
100
+ } else if (x === "polygon" || x === "polyline") {
101
+ const m = b.match(/\bpoints\s*=\s*["']([^"']+)["']/i);
102
+ m && r.push(v(m[1]));
103
+ }
104
+ }
105
+ r.length > 0 && (d.d = r.join(" "));
106
+ }
107
+ (d.d || e === "g") && a.push(d);
108
+ }
109
+ return { viewbox: o, elements: a, routePathDs: l };
110
+ }
111
+ function N(n) {
112
+ return n.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 80);
113
+ }
114
+ function O(n, t = "floor") {
115
+ const o = C(n), a = [], l = [], p = [], i = [], e = [];
116
+ let c = 0, k = 0, f = 0;
117
+ for (const g of o.elements) {
118
+ let { kind: d, guessed: s } = L(g.id, t);
119
+ g.interactive && !d && (d = "unit", s = !0);
120
+ const r = {
121
+ sourceSvgId: g.id,
122
+ kind: d,
123
+ guessed: s
124
+ };
125
+ if (!d) {
126
+ l.push(g.id), r.message = "No matching prefix; skipped", a.push(r);
127
+ continue;
128
+ }
129
+ if (!g.d) {
130
+ i.push(`Element ${g.id} has no drawable geometry`);
131
+ continue;
132
+ }
133
+ s && (p.push(r), r.message = "Guessed kind from interactive/fallback rule"), a.push(r), d === "walkable" && c++, d === "void" && k++, d === "unit" && f++;
134
+ const u = w([g.d], o.viewbox, !0), h = I(u);
135
+ e.push({
136
+ key: N(g.id),
137
+ kind: d,
138
+ geometry: u,
139
+ bbox: h,
140
+ sourceSvgId: g.id,
141
+ style: {}
142
+ });
143
+ }
144
+ return t === "floor" && c === 0 && i.push(
145
+ "No walkable layer found — auto-skeleton will be unavailable for this level"
146
+ ), {
147
+ report: {
148
+ classified: a,
149
+ unrecognized: l,
150
+ guessed: p,
151
+ walkableCount: c,
152
+ voidCount: k,
153
+ unitCount: f,
154
+ warnings: i
155
+ },
156
+ shapes: e,
157
+ viewbox: o.viewbox,
158
+ routePathDs: o.routePathDs
159
+ };
160
+ }
161
+ function T(n, t, o) {
162
+ const a = new Map(
163
+ t.filter((i) => i.sourceSvgId).map((i) => [i.sourceSvgId, i])
164
+ ), l = /* @__PURE__ */ new Set(), p = [];
165
+ for (const i of n) {
166
+ const e = a.get(i.sourceSvgId);
167
+ l.add(i.sourceSvgId), e ? e.kind !== i.kind ? p.push({
168
+ sourceSvgId: i.sourceSvgId,
169
+ change: "kind_changed",
170
+ existingShapeId: e.id,
171
+ existingKind: e.kind,
172
+ newKind: i.kind,
173
+ preserve: { key: e.key, assignment: !0, anchors: !0 }
174
+ }) : p.push({
175
+ sourceSvgId: i.sourceSvgId,
176
+ change: "unchanged",
177
+ existingShapeId: e.id,
178
+ existingKind: e.kind,
179
+ newKind: i.kind,
180
+ preserve: { key: e.key, assignment: !0, anchors: !0 }
181
+ }) : p.push({
182
+ sourceSvgId: i.sourceSvgId,
183
+ change: "added",
184
+ newKind: i.kind
185
+ });
186
+ }
187
+ for (const i of t)
188
+ i.sourceSvgId && !l.has(i.sourceSvgId) && p.push({
189
+ sourceSvgId: i.sourceSvgId,
190
+ change: "removed",
191
+ existingShapeId: i.id,
192
+ existingKind: i.kind
193
+ });
194
+ return {
195
+ items: p,
196
+ shapes: n,
197
+ viewbox: o
198
+ };
199
+ }
200
+ function F(n) {
201
+ const t = { ...S, ...n.theme }, o = new Map(
202
+ n.assignments.map((e) => [e.shapeId, e])
203
+ ), a = n.resolveSvgUrl ?? ((e) => e), l = n.levels.filter((e) => e.isActive).sort((e, c) => e.ordering - c.ordering).map((e) => {
204
+ const c = n.shapes.filter((f) => f.levelId === e.id).map((f) => ({
205
+ ...f,
206
+ assignment: o.get(f.id) ?? null
207
+ })), k = n.anchors.filter((f) => f.levelId === e.id);
208
+ return {
209
+ id: e.id,
210
+ buildingId: e.buildingId,
211
+ kind: e.kind,
212
+ name: e.name,
213
+ levelIndex: e.levelIndex,
214
+ ordering: e.ordering,
215
+ sourceSvgUrl: a(e.sourceSvgKey),
216
+ viewbox: e.sourceViewbox,
217
+ transform: e.transform,
218
+ shapes: c,
219
+ anchors: k
220
+ };
221
+ }), { nodes: p, edges: i } = E(
222
+ n.anchors,
223
+ n.edges,
224
+ n.connectors
225
+ );
226
+ return {
227
+ version: 2,
228
+ revisionId: n.revisionId,
229
+ revisionNumber: n.revisionNumber,
230
+ centerId: n.centerId,
231
+ mapId: n.mapId,
232
+ theme: t,
233
+ baseSvgUrl: n.baseSvgUrl,
234
+ baseViewbox: n.baseViewbox,
235
+ buildings: n.buildings,
236
+ levels: l,
237
+ connectors: n.connectors,
238
+ amenities: n.amenities.filter((e) => e.isActive),
239
+ graph: { nodes: p, edges: i },
240
+ responsiveOverrides: n.responsiveOverrides,
241
+ publishedAt: n.publishedAt ?? (/* @__PURE__ */ new Date()).toISOString()
242
+ };
243
+ }
244
+ export {
245
+ S as DEFAULT_THEME,
246
+ K as DEFAULT_WELD_TOLERANCE,
247
+ U as FLOOR_CHANGE_PENALTY,
248
+ z as INTERACTIVE_SHAPE_KINDS,
249
+ B as angleFromWall,
250
+ W as approximateCubic,
251
+ G as approximateQuadratic,
252
+ re as autoConnectUnitAnchor,
253
+ V as bboxOf,
254
+ H as bboxUnion,
255
+ ae as buildAutoSkeleton,
256
+ w as buildGeometryFromPaths,
257
+ j as centroid,
258
+ L as classifyId,
259
+ F as compileDocument,
260
+ E as compileGraph,
261
+ T as diffImport,
262
+ X as distance,
263
+ Z as findNearestAmenityPath,
264
+ Y as findPath,
265
+ ce as findWeldCandidates,
266
+ q as flipY,
267
+ I as geometryBBox,
268
+ Q as geometryCentroid,
269
+ de as importRoutePaths,
270
+ O as importSvg,
271
+ J as nearestPointOnPolyline,
272
+ C as parseSvgString,
273
+ y as parseViewBox,
274
+ ee as pathToPolygons,
275
+ ne as pointInPolygon,
276
+ ie as pointInPolygons,
277
+ se as projectOntoSegment,
278
+ te as snapAngle,
279
+ le as unitAnchorFromShape,
280
+ pe as weldAnchors
281
+ };
282
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/core/import/index.ts","../../src/core/publish/index.ts"],"sourcesContent":["import type {\n BBox,\n ImportClassification,\n ImportDiff,\n ImportDiffItem,\n ImportReport,\n ShapeGeometry,\n ShapeKind,\n ShapeStyle,\n ViewBox,\n} from '../types';\nimport {\n buildGeometryFromPaths,\n geometryBBox,\n parseViewBox,\n} from '../geometry';\n\n/** Prefix → shape kind for floor SVGs. */\nconst FLOOR_PREFIXES: Array<{ prefix: string; kind: ShapeKind }> = [\n { prefix: 'walkable', kind: 'walkable' },\n { prefix: 'void', kind: 'void' },\n { prefix: 'unit', kind: 'unit' },\n { prefix: 'store', kind: 'unit' }, // v1 compatibility\n { prefix: 'wall', kind: 'wall' },\n { prefix: 'boundary', kind: 'boundary' },\n { prefix: 'outer-wall', kind: 'wall' },\n { prefix: 'amenity-', kind: 'amenity' },\n { prefix: 'kiosk-', kind: 'kiosk_screen' },\n { prefix: 'escalator-', kind: 'connector' },\n { prefix: 'elevator-', kind: 'connector' },\n { prefix: 'stairs-', kind: 'connector' },\n { prefix: 'entrance-', kind: 'entrance' },\n { prefix: 'zone-', kind: 'zone' },\n { prefix: 'label-', kind: 'label' },\n { prefix: 'floorplate', kind: 'floorplate' },\n { prefix: 'base', kind: 'floorplate' },\n { prefix: 'decor', kind: 'decor' },\n { prefix: 'special-shape', kind: 'decor' },\n { prefix: 'overlay', kind: 'decor' },\n];\n\n/** Prefix → shape kind for outdoor / base layer. */\nconst BASE_PREFIXES: Array<{ prefix: string; kind: ShapeKind }> = [\n { prefix: 'parking-zone', kind: 'parking_zone' },\n { prefix: 'parking-lane', kind: 'parking_zone' },\n { prefix: 'parking-line', kind: 'decor' },\n { prefix: 'parking-icon', kind: 'parking_icon' },\n { prefix: 'green-area', kind: 'green_area' },\n { prefix: 'water', kind: 'water' },\n { prefix: 'decor', kind: 'decor' },\n { prefix: 'entrance-', kind: 'entrance' },\n { prefix: 'unit', kind: 'unit' },\n { prefix: 'store', kind: 'unit' },\n { prefix: 'interactive-', kind: 'unit' },\n { prefix: 'walkable', kind: 'walkable' },\n { prefix: 'amenity-', kind: 'amenity' },\n];\n\n/** v1 route-path lines are imported as route geometry, not shapes. */\nconst ROUTE_PATH_PREFIX = 'route-path';\n\nexport interface RawSvgElement {\n id: string;\n tag: string;\n d?: string;\n points?: string;\n x1?: number;\n y1?: number;\n x2?: number;\n y2?: number;\n interactive?: boolean;\n}\n\nexport interface ParsedSvg {\n viewbox: ViewBox | null;\n elements: RawSvgElement[];\n routePathDs: string[];\n}\n\nexport function classifyId(\n id: string,\n mode: 'floor' | 'base' = 'floor',\n): { kind: ShapeKind | null; guessed: boolean } {\n const lower = id.toLowerCase();\n const table = mode === 'base' ? BASE_PREFIXES : FLOOR_PREFIXES;\n for (const { prefix, kind } of table) {\n if (lower === prefix || lower.startsWith(prefix)) {\n return { kind, guessed: false };\n }\n }\n // interactive-* or data-interactive attribute handled by caller\n if (lower.startsWith('interactive')) {\n return { kind: 'unit', guessed: true };\n }\n return { kind: null, guessed: false };\n}\n\nfunction pointsToPath(points: string): string {\n const nums = points.trim().split(/[\\s,]+/).map(Number);\n if (nums.length < 4) return '';\n let d = `M ${nums[0]} ${nums[1]}`;\n for (let i = 2; i < nums.length; i += 2) {\n d += ` L ${nums[i]} ${nums[i + 1]}`;\n }\n d += ' Z';\n return d;\n}\n\nfunction lineToPath(x1: number, y1: number, x2: number, y2: number): string {\n return `M ${x1} ${y1} L ${x2} ${y2}`;\n}\n\n/**\n * Lightweight SVG string parser — no DOM required (works in Node).\n * Extracts elements with id attributes and path-like geometry.\n */\nexport function parseSvgString(svg: string): ParsedSvg {\n const viewboxMatch = svg.match(/viewBox\\s*=\\s*[\"']([^\"']+)[\"']/i);\n const viewbox = parseViewBox(viewboxMatch?.[1]);\n\n const elements: RawSvgElement[] = [];\n const routePathDs: string[] = [];\n\n // Match tagged elements that may carry an id\n const tagRe =\n /<(path|polygon|polyline|line|rect|g)\\b([^>]*)(?:\\/>|>([\\s\\S]*?)<\\/\\1>)/gi;\n let match: RegExpExecArray | null;\n while ((match = tagRe.exec(svg)) !== null) {\n const tag = match[1].toLowerCase();\n const attrs = match[2] ?? '';\n const idMatch = attrs.match(/\\bid\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (!idMatch) continue;\n const id = idMatch[1];\n const interactive = /\\bdata-interactive\\s*=\\s*[\"']?(true|1|yes)/i.test(attrs);\n\n if (id.toLowerCase().startsWith(ROUTE_PATH_PREFIX)) {\n const dMatch = attrs.match(/\\bd\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (dMatch) routePathDs.push(dMatch[1]);\n const pointsMatch = attrs.match(/\\bpoints\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (pointsMatch) routePathDs.push(pointsToPath(pointsMatch[1]).replace(/ Z$/, ''));\n continue;\n }\n\n const el: RawSvgElement = { id, tag, interactive };\n\n if (tag === 'path') {\n const dMatch = attrs.match(/\\bd\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (dMatch) el.d = dMatch[1];\n } else if (tag === 'polygon' || tag === 'polyline') {\n const pointsMatch = attrs.match(/\\bpoints\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (pointsMatch) el.d = pointsToPath(pointsMatch[1]);\n } else if (tag === 'line') {\n const num = (name: string) => {\n const m = attrs.match(new RegExp(`\\\\b${name}\\\\s*=\\\\s*[\"']?(-?[\\\\d.]+)`, 'i'));\n return m ? Number(m[1]) : 0;\n };\n el.d = lineToPath(num('x1'), num('y1'), num('x2'), num('y2'));\n } else if (tag === 'rect') {\n const num = (name: string) => {\n const m = attrs.match(new RegExp(`\\\\b${name}\\\\s*=\\\\s*[\"']?(-?[\\\\d.]+)`, 'i'));\n return m ? Number(m[1]) : 0;\n };\n const x = num('x');\n const y = num('y');\n const w = num('width');\n const h = num('height');\n el.d = `M ${x} ${y} L ${x + w} ${y} L ${x + w} ${y + h} L ${x} ${y + h} Z`;\n } else if (tag === 'g') {\n // Collect child paths under this group id\n const inner = match[3] ?? '';\n const childPaths: string[] = [];\n const childRe = /<(path|polygon|polyline|line|rect)\\b([^>]*)\\/?>/gi;\n let cm: RegExpExecArray | null;\n while ((cm = childRe.exec(inner)) !== null) {\n const ctag = cm[1].toLowerCase();\n const cattrs = cm[2] ?? '';\n if (ctag === 'path') {\n const dm = cattrs.match(/\\bd\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (dm) childPaths.push(dm[1]);\n } else if (ctag === 'polygon' || ctag === 'polyline') {\n const pm = cattrs.match(/\\bpoints\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (pm) childPaths.push(pointsToPath(pm[1]));\n }\n }\n if (childPaths.length > 0) {\n el.d = childPaths.join(' ');\n }\n }\n\n if (el.d || tag === 'g') {\n elements.push(el);\n }\n }\n\n return { viewbox, elements, routePathDs };\n}\n\nexport interface ImportedShapeDraft {\n key: string;\n kind: ShapeKind;\n geometry: ShapeGeometry;\n bbox: BBox;\n sourceSvgId: string;\n style: ShapeStyle;\n}\n\nfunction slugKey(id: string): string {\n return id\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 80);\n}\n\nexport function importSvg(\n svg: string,\n mode: 'floor' | 'base' = 'floor',\n): { report: ImportReport; shapes: ImportedShapeDraft[]; viewbox: ViewBox | null; routePathDs: string[] } {\n const parsed = parseSvgString(svg);\n const classified: ImportClassification[] = [];\n const unrecognized: string[] = [];\n const guessed: ImportClassification[] = [];\n const warnings: string[] = [];\n const shapes: ImportedShapeDraft[] = [];\n\n let walkableCount = 0;\n let voidCount = 0;\n let unitCount = 0;\n\n for (const el of parsed.elements) {\n let { kind, guessed: isGuessed } = classifyId(el.id, mode);\n if (el.interactive && !kind) {\n kind = 'unit';\n isGuessed = true;\n }\n\n const entry: ImportClassification = {\n sourceSvgId: el.id,\n kind,\n guessed: isGuessed,\n };\n\n if (!kind) {\n unrecognized.push(el.id);\n entry.message = 'No matching prefix; skipped';\n classified.push(entry);\n continue;\n }\n\n if (!el.d) {\n warnings.push(`Element ${el.id} has no drawable geometry`);\n continue;\n }\n\n if (isGuessed) {\n guessed.push(entry);\n entry.message = 'Guessed kind from interactive/fallback rule';\n }\n classified.push(entry);\n\n if (kind === 'walkable') walkableCount++;\n if (kind === 'void') voidCount++;\n if (kind === 'unit') unitCount++;\n\n const geometry = buildGeometryFromPaths([el.d], parsed.viewbox, true);\n const bbox = geometryBBox(geometry);\n\n shapes.push({\n key: slugKey(el.id),\n kind,\n geometry,\n bbox,\n sourceSvgId: el.id,\n style: {},\n });\n }\n\n if (mode === 'floor' && walkableCount === 0) {\n warnings.push(\n 'No walkable layer found — auto-skeleton will be unavailable for this level',\n );\n }\n\n return {\n report: {\n classified,\n unrecognized,\n guessed,\n walkableCount,\n voidCount,\n unitCount,\n warnings,\n },\n shapes,\n viewbox: parsed.viewbox,\n routePathDs: parsed.routePathDs,\n };\n}\n\nexport interface ExistingShapeRef {\n id: number;\n sourceSvgId: string | null;\n kind: ShapeKind;\n key: string;\n}\n\n/**\n * Diff newly imported shapes against existing level shapes by source_svg_id.\n */\nexport function diffImport(\n imported: ImportedShapeDraft[],\n existing: ExistingShapeRef[],\n viewbox: ViewBox | null,\n): ImportDiff {\n const existingBySource = new Map(\n existing\n .filter((e) => e.sourceSvgId)\n .map((e) => [e.sourceSvgId as string, e]),\n );\n const seen = new Set<string>();\n const items: ImportDiffItem[] = [];\n\n for (const shape of imported) {\n const prev = existingBySource.get(shape.sourceSvgId);\n seen.add(shape.sourceSvgId);\n if (!prev) {\n items.push({\n sourceSvgId: shape.sourceSvgId,\n change: 'added',\n newKind: shape.kind,\n });\n } else if (prev.kind !== shape.kind) {\n items.push({\n sourceSvgId: shape.sourceSvgId,\n change: 'kind_changed',\n existingShapeId: prev.id,\n existingKind: prev.kind,\n newKind: shape.kind,\n preserve: { key: prev.key, assignment: true, anchors: true },\n });\n } else {\n items.push({\n sourceSvgId: shape.sourceSvgId,\n change: 'unchanged',\n existingShapeId: prev.id,\n existingKind: prev.kind,\n newKind: shape.kind,\n preserve: { key: prev.key, assignment: true, anchors: true },\n });\n }\n }\n\n for (const prev of existing) {\n if (prev.sourceSvgId && !seen.has(prev.sourceSvgId)) {\n items.push({\n sourceSvgId: prev.sourceSvgId,\n change: 'removed',\n existingShapeId: prev.id,\n existingKind: prev.kind,\n });\n }\n }\n\n return {\n items,\n shapes: imported,\n viewbox,\n };\n}\n","import type {\n CmAmenityCatalogItem,\n CmAnchor,\n CmBuilding,\n CmConnector,\n CmLevel,\n CmResponsiveOverride,\n CmRouteEdge,\n CmShape,\n CmShapeAssignment,\n PublishedDocument,\n ThemeDefaults,\n ViewBox,\n} from '../types';\nimport { DEFAULT_THEME } from '../types';\nimport { compileGraph } from '../routing/pathfinding';\n\nexport interface PublishInput {\n revisionId: number;\n revisionNumber: number;\n centerId: number;\n mapId: number;\n theme: Partial<ThemeDefaults>;\n baseSvgUrl: string | null;\n baseViewbox: ViewBox | null;\n buildings: CmBuilding[];\n levels: CmLevel[];\n shapes: CmShape[];\n assignments: CmShapeAssignment[];\n anchors: CmAnchor[];\n edges: CmRouteEdge[];\n connectors: CmConnector[];\n amenities: CmAmenityCatalogItem[];\n responsiveOverrides: CmResponsiveOverride[];\n /** Resolve S3 key → CDN URL for level source SVGs. */\n resolveSvgUrl?: (key: string | null) => string | null;\n publishedAt?: string;\n}\n\n/**\n * Compile draft rows into an immutable published document.\n * Used by both the admin publish endpoint and the draft preview (?draft=1).\n */\nexport function compileDocument(input: PublishInput): PublishedDocument {\n const theme: ThemeDefaults = { ...DEFAULT_THEME, ...input.theme };\n const assignmentByShape = new Map(\n input.assignments.map((a) => [a.shapeId, a]),\n );\n const resolve = input.resolveSvgUrl ?? ((k: string | null) => k);\n\n const levels = input.levels\n .filter((l) => l.isActive)\n .sort((a, b) => a.ordering - b.ordering)\n .map((level) => {\n const levelShapes = input.shapes\n .filter((s) => s.levelId === level.id)\n .map((s) => ({\n ...s,\n assignment: assignmentByShape.get(s.id) ?? null,\n }));\n const levelAnchors = input.anchors.filter((a) => a.levelId === level.id);\n return {\n id: level.id,\n buildingId: level.buildingId,\n kind: level.kind,\n name: level.name,\n levelIndex: level.levelIndex,\n ordering: level.ordering,\n sourceSvgUrl: resolve(level.sourceSvgKey),\n viewbox: level.sourceViewbox,\n transform: level.transform,\n shapes: levelShapes,\n anchors: levelAnchors,\n };\n });\n\n const { nodes, edges } = compileGraph(\n input.anchors,\n input.edges,\n input.connectors,\n );\n\n return {\n version: 2,\n revisionId: input.revisionId,\n revisionNumber: input.revisionNumber,\n centerId: input.centerId,\n mapId: input.mapId,\n theme,\n baseSvgUrl: input.baseSvgUrl,\n baseViewbox: input.baseViewbox,\n buildings: input.buildings,\n levels,\n connectors: input.connectors,\n amenities: input.amenities.filter((a) => a.isActive),\n graph: { nodes, edges },\n responsiveOverrides: input.responsiveOverrides,\n publishedAt: input.publishedAt ?? new Date().toISOString(),\n };\n}\n"],"names":["FLOOR_PREFIXES","BASE_PREFIXES","ROUTE_PATH_PREFIX","classifyId","id","mode","lower","table","prefix","kind","pointsToPath","points","nums","d","i","lineToPath","x1","y1","x2","y2","parseSvgString","svg","viewboxMatch","viewbox","parseViewBox","elements","routePathDs","tagRe","match","tag","attrs","idMatch","interactive","dMatch","pointsMatch","el","num","name","m","x","y","w","h","inner","childPaths","childRe","cm","ctag","cattrs","dm","pm","slugKey","importSvg","parsed","classified","unrecognized","guessed","warnings","shapes","walkableCount","voidCount","unitCount","isGuessed","entry","geometry","buildGeometryFromPaths","bbox","geometryBBox","diffImport","imported","existing","existingBySource","e","seen","items","shape","prev","compileDocument","input","theme","DEFAULT_THEME","assignmentByShape","a","resolve","k","levels","l","b","level","levelShapes","s","levelAnchors","nodes","edges","compileGraph"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { CmAmenityCatalogItem, CmAnchor, CmBuilding, CmConnector, CmLevel, CmResponsiveOverride, CmRouteEdge, CmShape, CmShapeAssignment, PublishedDocument, ThemeDefaults, ViewBox } from '../types';
2
+ export interface PublishInput {
3
+ revisionId: number;
4
+ revisionNumber: number;
5
+ centerId: number;
6
+ mapId: number;
7
+ theme: Partial<ThemeDefaults>;
8
+ baseSvgUrl: string | null;
9
+ baseViewbox: ViewBox | null;
10
+ buildings: CmBuilding[];
11
+ levels: CmLevel[];
12
+ shapes: CmShape[];
13
+ assignments: CmShapeAssignment[];
14
+ anchors: CmAnchor[];
15
+ edges: CmRouteEdge[];
16
+ connectors: CmConnector[];
17
+ amenities: CmAmenityCatalogItem[];
18
+ responsiveOverrides: CmResponsiveOverride[];
19
+ /** Resolve S3 key → CDN URL for level source SVGs. */
20
+ resolveSvgUrl?: (key: string | null) => string | null;
21
+ publishedAt?: string;
22
+ }
23
+ /**
24
+ * Compile draft rows into an immutable published document.
25
+ * Used by both the admin publish endpoint and the draft preview (?draft=1).
26
+ */
27
+ export declare function compileDocument(input: PublishInput): PublishedDocument;
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/publish/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,QAAQ,EACR,UAAU,EACV,WAAW,EACX,OAAO,EACP,oBAAoB,EACpB,WAAW,EACX,OAAO,EACP,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,OAAO,EACR,MAAM,UAAU,CAAC;AAIlB,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,SAAS,EAAE,oBAAoB,EAAE,CAAC;IAClC,mBAAmB,EAAE,oBAAoB,EAAE,CAAC;IAC5C,sDAAsD;IACtD,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,iBAAiB,CAwDtE"}
@@ -0,0 +1,47 @@
1
+ import { AutoConnectResult, CmAnchor, CmRouteEdge, SkeletonSuggestion, Vec2, WeldResult } from '../types';
2
+ export interface AnchorLike {
3
+ id: number;
4
+ x: number;
5
+ y: number;
6
+ levelId: number;
7
+ shapeId?: number | null;
8
+ kind?: string;
9
+ }
10
+ export interface EdgeLike {
11
+ id: number;
12
+ fromAnchorId: number;
13
+ toAnchorId: number;
14
+ }
15
+ /**
16
+ * Weld anchors within tolerance into the surviving (lowest id) anchor.
17
+ * Rewires edges that referenced removed anchors.
18
+ */
19
+ export declare function weldAnchors(anchors: AnchorLike[], edges: EdgeLike[], candidateIds: number[], tolerance?: number): WeldResult | null;
20
+ /**
21
+ * Find all pairs of anchors within tolerance that should be welded.
22
+ */
23
+ export declare function findWeldCandidates(anchors: AnchorLike[], tolerance?: number): number[][];
24
+ /**
25
+ * Auto-connect a unit anchor to the nearest walkable segment via perpendicular projection.
26
+ */
27
+ export declare function autoConnectUnitAnchor(unitAnchor: AnchorLike, walkablePolylines: Vec2[][], existingJunctions: AnchorLike[], weldTolerance?: number): AutoConnectResult | null;
28
+ /**
29
+ * Place a unit anchor at the centroid of a shape's polygons, if the point lies inside.
30
+ */
31
+ export declare function unitAnchorFromShape(shapeId: number, levelId: number, polygons: Vec2[][], tempId: number): CmAnchor | null;
32
+ /**
33
+ * Build a simple medial-axis-ish skeleton from walkable polygons minus voids.
34
+ * This is a pragmatic approximation: sample a grid inside walkable, reject void cells,
35
+ * connect adjacent free cells into a sparse graph, then prune to a polyline network.
36
+ */
37
+ export declare function buildAutoSkeleton(walkablePolygons: Vec2[][], voidPolygons: Vec2[][], cellSize?: number): SkeletonSuggestion;
38
+ /**
39
+ * Convert route-path SVG line endpoints into welded anchors + edges.
40
+ * This is the key converter step that repairs coincident-but-disconnected joins.
41
+ */
42
+ export declare function importRoutePaths(pathDs: string[], levelId: number, mapId: number, startId: number, weldTolerance?: number, viewboxHeight?: number): {
43
+ anchors: CmAnchor[];
44
+ edges: CmRouteEdge[];
45
+ nextId: number;
46
+ };
47
+ //# sourceMappingURL=graph-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-tools.d.ts","sourceRoot":"","sources":["../../../src/core/routing/graph-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,kBAAkB,EAClB,IAAI,EACJ,UAAU,EACX,MAAM,UAAU,CAAC;AASlB,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,UAAU,EAAE,EACrB,KAAK,EAAE,QAAQ,EAAE,EACjB,YAAY,EAAE,MAAM,EAAE,EACtB,SAAS,SAAyB,GACjC,UAAU,GAAG,IAAI,CA2CnB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,UAAU,EAAE,EACrB,SAAS,SAAyB,GACjC,MAAM,EAAE,EAAE,CAuBZ;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,UAAU,EACtB,iBAAiB,EAAE,IAAI,EAAE,EAAE,EAC3B,iBAAiB,EAAE,UAAU,EAAE,EAC/B,aAAa,SAAyB,GACrC,iBAAiB,GAAG,IAAI,CA6B1B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,IAAI,EAAE,EAAE,EAClB,MAAM,EAAE,MAAM,GACb,QAAQ,GAAG,IAAI,CAyBjB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,gBAAgB,EAAE,IAAI,EAAE,EAAE,EAC1B,YAAY,EAAE,IAAI,EAAE,EAAE,EACtB,QAAQ,SAAK,GACZ,kBAAkB,CA4DpB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,aAAa,SAAyB,EACtC,aAAa,CAAC,EAAE,MAAM,GACrB;IAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAAC,KAAK,EAAE,WAAW,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAoD/D"}