File size: 5,012 Bytes
5c8d4fd
 
 
 
 
 
 
 
 
a99e3c4
 
 
 
 
 
 
 
 
 
 
569908e
5c8d4fd
 
 
 
354747c
2b6f63a
 
 
 
 
569908e
 
 
 
 
 
a99e3c4
 
 
569908e
 
5c8d4fd
 
569908e
 
2b6f63a
 
 
 
 
 
5c8d4fd
569908e
 
2b6f63a
 
 
 
 
 
 
 
 
 
 
 
5c8d4fd
2b6f63a
569908e
5c8d4fd
 
569908e
 
5c8d4fd
 
 
 
 
 
2b6f63a
 
 
 
 
 
 
 
 
 
5c8d4fd
 
 
 
569908e
 
5c8d4fd
569908e
 
5c8d4fd
 
569908e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5c8d4fd
 
 
 
 
 
 
 
569908e
 
5c8d4fd
569908e
 
5c8d4fd
 
 
569908e
5c8d4fd
569908e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354747c
569908e
 
 
 
 
 
 
 
 
5c8d4fd
 
 
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>DCM Assembly Visualizer</title>
  <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
  <style>
    body { font-family: sans-serif; padding: 20px; margin: 0; box-sizing: border-box; }
    #plot-wrapper {
      width: 100%;
      height: calc(100vh - 200px);
      border: 2px dashed #999;
      display: flex;
      align-items: center;
      justify-content: center;
      background-color: #fafafa;
    }
    #plot { width: 100%; height: 100%; }
    .controls { width: 200px; margin-right: 20px; }
  </style>
</head>
<body>
  <h1>DCM Assembly Visualizer</h1>

  <input type="file" id="file1" accept=".txt"> File A<br>
  <input type="file" id="file2" accept=".txt"> File B<br>
  <button onclick="uploadFiles()">Visualize</button>

  <div style="display: flex; margin-top: 20px;">
    <div class="controls">
      <h3>Controls</h3>
      <div id="partControls"></div>
      <label><input type="checkbox" id="toggleConstraints" checked onchange="toggleConstraints()"> Show Constraints</label>
    </div>
    <div style="flex: 1;">
      <div id="plot-wrapper">
        <div id="plot"></div>
      </div>
    </div>
  </div>

  <script>
    let allTraces = [];
    let constraintTraces = [];
    let partMap = {};

    async function uploadFiles() {
      const file1 = document.getElementById("file1").files[0];
      const file2 = document.getElementById("file2").files[0];
      if (!file1 && !file2) return alert("Please select at least one file.");

      allTraces = [];
      constraintTraces = [];
      partMap = [];

      const payload = [];

      if (file1) {
        const data = await sendFile(file1);
        payload.push(["red", "blue", data]);
      }
      if (file2) {
        const data = await sendFile(file2);
        payload.push(["orange", "purple", data]);
      }

      for (const [color, label, data] of payload) {
        extractTraces(data, color, label);
      }

      renderPartControls();
      Plotly.newPlot('plot', [...allTraces, ...constraintTraces], {
        margin: { t: 30 },
        scene: { aspectmode: 'data' },
        title: '3D Assembly Viewer'
      });
    }

    async function sendFile(file) {
      const formData = new FormData();
      formData.append("file", file);
      const res = await fetch("/parse", {
        method: "POST",
        body: formData
      });
      return await res.json();
    }

    function extractTraces(data, baseColor, normalColor) {
      for (const [tag, g] of Object.entries(data.geometry)) {
        const [x, y, z] = g.base_point;
        const [nx, ny, nz] = g.normal;
        const label = g.label || tag;
        const part = label.split('@').pop()?.split('-')[0] || "unknown";

        const baseTrace = {
          type: 'scatter3d', mode: 'markers+text',
          x: [x], y: [y], z: [z],
          marker: { color: baseColor, size: 5 },
          text: [label], textposition: 'top center',
          name: `Base: ${label}`
        };

        const normalTrace = {
          type: 'scatter3d', mode: 'lines',
          x: [x, x + nx], y: [y, y + ny], z: [z, z + nz],
          line: { color: normalColor, width: 2 },
          name: `Normal: ${label}`
        };

        const baseIndex = allTraces.length;
        allTraces.push(baseTrace);
        allTraces.push(normalTrace);

        if (!partMap[part]) partMap[part] = [];
        partMap[part].push(baseIndex, baseIndex + 1);
      }

      for (const c of data.constraints) {
        const g1 = data.geometry[c.from];
        const g2 = data.geometry[c.to];
        if (g1 && g2) {
          const [x1, y1, z1] = g1.base_point;
          const [x2, y2, z2] = g2.base_point;
          constraintTraces.push({
            type: 'scatter3d', mode: 'lines',
            x: [x1, x2], y: [y1, y2], z: [z1, z2],
            line: { color: 'green', dash: 'dot', width: 2 },
            name: `Constraint: ${c.label || ''}`
          });
        }
      }
    }

    function renderPartControls() {
      const container = document.getElementById("partControls");
      container.innerHTML = '';
      for (const part in partMap) {
        const id = `part_${part}`;
        container.innerHTML += `<label><input type='checkbox' id='${id}' checked onchange='togglePart("${part}")'> ${part}</label><br>`;
      }
    }

    function togglePart(part) {
      const indices = partMap[part];
      const visible = document.getElementById(`part_${part}`).checked;
      for (const i of indices) {
        Plotly.restyle('plot', { visible: visible }, [i]);
      }
    }

    function toggleConstraints() {
      const show = document.getElementById("toggleConstraints").checked;
      const start = allTraces.length;
      const end = start + constraintTraces.length;
      for (let i = start; i < end; i++) {
        Plotly.restyle('plot', { visible: show }, [i]);
      }
    }
  </script>
</body>
</html>