File size: 3,875 Bytes
1e3df84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e0e4431
 
 
 
 
 
 
1e3df84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e0e4431
1e3df84
 
 
 
 
 
 
 
 
 
 
e0e4431
1e3df84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
"""
Convert Tesseract++ graph JSON to Cytoscape.js elements format.

Tesseract++ JSON format:
  nodes: [{id, type, position: [x,y], floor, ...}, ...]
  edges: [{source, target, weight, distance}, ...]

Cytoscape.js elements format:
  nodes: [{data: {id, type, floor, ...}, position: {x, y}}, ...]
  edges: [{data: {id, source, target, weight, edgeColorType}, ...}, ...]
"""

from typing import Dict, Any, List


def _norm_type(t: str) -> str:
    """Normalize node types for the frontend. The pipeline emits 'transition'
    for stairs/elevators, but the UI keys color, shape, size, and labels on
    'floor_transition'. Map them so everything stays consistent."""
    return "floor_transition" if t == "transition" else t


def _determine_edge_color_type(
    source_id: str,
    target_id: str,
    node_type_map: Dict[str, str]
) -> str:
    """Determine edge color category based on endpoint node types."""
    src_type = node_type_map.get(source_id, "unknown")
    tgt_type = node_type_map.get(target_id, "unknown")

    types = {src_type, tgt_type}

    if "floor_transition" in types:
        return "transition"
    if "outside" in types:
        return "outside"
    if "corridor" in types:
        return "corridor"
    if "room" in types:
        return "room"
    return "default"


def convert_to_cytoscape(graph_json: Dict[str, Any]) -> Dict[str, Any]:
    """
    Convert Tesseract++ graph JSON to Cytoscape.js elements format.

    Args:
        graph_json: Raw graph dict with 'nodes' and 'edges' lists.

    Returns:
        Dict with 'nodes', 'edges', and 'layout' keys in Cytoscape format.
    """
    raw_nodes = graph_json.get("nodes", [])
    raw_edges = graph_json.get("edges", [])

    # Build node type lookup for edge coloring
    node_type_map: Dict[str, str] = {}
    for node in raw_nodes:
        node_type_map[node["id"]] = _norm_type(node.get("type", "unknown"))

    # Convert nodes
    cy_nodes: List[Dict[str, Any]] = []
    for node in raw_nodes:
        pos = node.get("position", [0, 0])
        x = pos[0] if isinstance(pos, (list, tuple)) else pos.get("x", 0)
        y = pos[1] if isinstance(pos, (list, tuple)) else pos.get("y", 0)

        data: Dict[str, Any] = {
            "id": node["id"],
            "label": node["id"],
            "type": _norm_type(node.get("type", "unknown")),
            "floor": node.get("floor", ""),
        }

        # Add room-specific attributes
        if node.get("type") == "room":
            if "room_area_px" in node:
                data["area"] = node["room_area_px"]
            if "anchor_door" in node:
                data["anchorDoor"] = node["anchor_door"]
            if "room_eq_radius" in node:
                data["eqRadius"] = round(node["room_eq_radius"], 1)

        # Add subnode info
        if node.get("is_subnode"):
            data["isSubnode"] = True
            data["parentRoom"] = node.get("parent_room_id", "")

        # Add door-specific attributes
        if node.get("type") == "door":
            if "door_type" in node:
                data["doorType"] = node["door_type"]

        cy_nodes.append({
            "data": data,
            "position": {"x": float(x), "y": float(y)}
        })

    # Convert edges
    cy_edges: List[Dict[str, Any]] = []
    for idx, edge in enumerate(raw_edges):
        source = edge["source"]
        target = edge["target"]
        edge_id = f"e{idx}_{source}_{target}"

        color_type = _determine_edge_color_type(source, target, node_type_map)

        cy_edges.append({
            "data": {
                "id": edge_id,
                "source": source,
                "target": target,
                "weight": edge.get("weight", 1.0),
                "edgeColorType": color_type
            }
        })

    return {
        "nodes": cy_nodes,
        "edges": cy_edges,
        "layout": "preset"
    }