44
55#pragma once
66
7+ #include < fstream>
78#include < vector>
89#include < string>
910#include < sstream>
@@ -25,7 +26,7 @@ namespace webifc::dump
2526<head>
2627 <meta charset="UTF-8">
2728 <meta name="viewport" content="width=device-width, initial-scale=1.0">
28- <title>DumpCurveToHtml </title>
29+ <title>IFC Geometry Viewer </title>
2930 <style>
3031 body { margin: 0; overflow: hidden; }
3132 canvas { display: block; }
@@ -47,7 +48,7 @@ namespace webifc::dump
4748 const controls = new THREE.OrbitControls(camera, renderer.domElement);
4849 controls.enableDamping = true;
4950 controls.dampingFactor = 0.05;
50- controls.screenSpacePanning = true; // Allow panning in XY plane
51+ controls.screenSpacePanning = true;
5152 controls.minDistance = 1;
5253 controls.maxDistance = 500;
5354 controls.mouseButtons = {
@@ -57,21 +58,34 @@ namespace webifc::dump
5758 };
5859 controls.enablePan = true;
5960 controls.panSpeed = 0.5;
60- controls.up = new THREE.Vector3(0, 0, 1); // Ensure Z is up for rotations
61- const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
61+ controls.up = new THREE.Vector3(0, 0, 1);
62+
63+ // Lighting setup
64+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.4); // Soft ambient light
6265 scene.add(ambientLight);
63- const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
64- directionalLight.position.set(1, 1, 1);
65- scene.add(directionalLight);
66+ const directionalLight1 = new THREE.DirectionalLight(0xffffff, 0.6); // Primary light
67+ directionalLight1.position.set(1, 1, 1).normalize();
68+ scene.add(directionalLight1);
69+ const directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.4); // Secondary light to reduce shadows
70+ directionalLight2.position.set(-1, -1, 1).normalize();
71+ scene.add(directionalLight2);
6672
6773 const objData = "{}";
68- const blackMaterial = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 2 });
69- const grayMaterial = new THREE.LineBasicMaterial({ color: 0x888888, linewidth: 2 });
74+ const meshMaterial = new THREE.MeshStandardMaterial({
75+ color: 0x888888,
76+ roughness: 0.7,
77+ metalness: 0.1,
78+ side: THREE.DoubleSide ,
79+ opacity: 0.7
80+ });
81+ const lineMaterial = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 2 });
82+ const edgeMaterial = new THREE.LineBasicMaterial({ color: 0x333333, linewidth: 2 });
7083
71- // Parse OBJ data manually to create individual line segments
84+ // Parse OBJ data for vertices, lines, and faces
7285 function parseOBJ(objText) {
7386 const vertices = [];
7487 const lines = [];
88+ const faces = [];
7589 const linesArray = objText.split('\n');
7690 linesArray.forEach(line => {
7791 line = line.trim();
@@ -80,37 +94,70 @@ namespace webifc::dump
8094 vertices.push(new THREE.Vector3(parts[0], parts[1], parts[2]));
8195 } else if (line.startsWith('l ')) {
8296 const indices = line.split(/\s+/).slice(1).map(i => parseInt(i) - 1);
83- lines.push(indices);
97+ if (indices.length >= 2) {
98+ lines.push(indices);
99+ }
100+ } else if (line.startsWith('f ')) {
101+ const indices = line.split(/\s+/).slice(1).map(part => parseInt(part.split('/')[0]) - 1);
102+ if (indices.length >= 3) {
103+ faces.push(indices.slice(0, 3)); // Only triangles
104+ }
84105 }
85106 });
86- return { vertices, lines };
107+ return { vertices, lines, faces };
87108 }
88109
89- // Create individual Line objects for each segment
90- const { vertices, lines } = parseOBJ(objData);
110+ // Create mesh if faces exist
111+ const { vertices, lines, faces } = parseOBJ(objData);
112+ if (faces.length > 0) {
113+ const geometry = new THREE.BufferGeometry();
114+ const positions = new Float32Array(vertices.length * 3);
115+ const indices = new Uint32Array(faces.length * 3);
116+ vertices.forEach((v, i) => {
117+ positions[i * 3] = v.x;
118+ positions[i * 3 + 1] = v.y;
119+ positions[i * 3 + 2] = v.z;
120+ });
121+ faces.forEach((f, i) => {
122+ indices[i * 3] = f[0];
123+ indices[i * 3 + 1] = f[1];
124+ indices[i * 3 + 2] = f[2];
125+ });
126+ geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
127+ geometry.setIndex(new THREE.BufferAttribute(indices, 1));
128+ geometry.computeVertexNormals();
129+ const mesh = new THREE.Mesh(geometry, meshMaterial);
130+ scene.add(mesh);
131+
132+ // Add wireframe lines for triangle edges
133+ const edges = new THREE.EdgesGeometry(geometry, 1); // Threshold angle of 1 degree
134+ const edgeLines = new THREE.LineSegments(edges, edgeMaterial);
135+ scene.add(edgeLines);
136+ }
137+
138+ // Create lines if lines exist
91139 lines.forEach((lineIndices, index) => {
92140 const geometry = new THREE.BufferGeometry().setFromPoints([
93141 vertices[lineIndices[0]],
94142 vertices[lineIndices[1]]
95143 ]);
96- const material = (index % 2 === 0) ? blackMaterial : grayMaterial;
97- const line = new THREE.Line(geometry, material);
144+ const line = new THREE.Line(geometry, lineMaterial);
98145 scene.add(line);
99146 });
100147
101- // Compute bounding box from vertices
148+ // Compute bounding box
102149 const box = new THREE.Box3();
103150 vertices.forEach(vertex => box.expandByPoint(vertex));
104151 const minPoint = box.min;
105152 const center = box.getCenter(new THREE.Vector3());
106153
107- // Add XY grid (10x10 lines , 10m spacing, 100x100m total) in XY plane at Z=0, positioned at minPoint
154+ // Add XY grid (100x100m , 10m spacing) at Z=min
108155 const grid = new THREE.GridHelper(100, 10, 0x888888, 0x888888);
109- grid.rotation.x = -Math.PI / 2; // Rotate grid to lie in XY plane with Z up
110- grid.position.set(minPoint.x, minPoint.y, minPoint.z); // Position at min point
156+ grid.rotation.x = -Math.PI / 2;
157+ grid.position.set(minPoint.x, minPoint.y, minPoint.z);
111158 scene.add(grid);
112159
113- // Add coordinate axes (X: red, Y: green, Z: blue, 200m length), positioned at minPoint
160+ // Add coordinate axes (X: red, Y: green, Z: blue, 200m length)
114161 const axesGroup = new THREE.Group();
115162 axesGroup.position.set(minPoint.x, minPoint.y, minPoint.z);
116163 const axesMaterialX = new THREE.LineBasicMaterial({ color: 0xff0000 });
@@ -133,13 +180,24 @@ namespace webifc::dump
133180 axesGroup.add(zAxis);
134181 scene.add(axesGroup);
135182
136- // Zoom to the bounding box
183+ // Zoom to bounding box
137184 const size = box.getSize(new THREE.Vector3());
138- const maxDim = Math.max(size.x, size.y, size.z);
185+ let maxDim = Math.max(size.x, size.y, size.z);
186+ if (maxDim < 0.0001) {
187+ maxDim = 1; // Prevent division by zero
188+ }
189+ const aspect = window.innerWidth / window.innerHeight;
139190 const fov = camera.fov * (Math.PI / 180);
140- let cameraDistance = maxDim / Math.tan(fov / 2);
191+ const fovHorizontal = 2 * Math.atan(Math.tan(fov / 2) * aspect);
192+ const maxDimHorizontal = Math.max(size.x, size.y);
193+ let cameraDistance = Math.max(
194+ maxDim / Math.tan(fov / 2),
195+ maxDimHorizontal / Math.tan(fovHorizontal / 2)
196+ );
141197 cameraDistance *= 1.1; // Padding
142- camera.position.set(center.x, center.y, center.z + cameraDistance);
198+ cameraDistance = Math.max(cameraDistance, camera.near * 1.1);
199+ const offset = cameraDistance / Math.sqrt(3);
200+ camera.position.set(center.x + offset, center.y + offset, center.z + offset);
143201 camera.lookAt(center);
144202 controls.target.copy(center);
145203
@@ -464,7 +522,7 @@ namespace webifc::dump
464522 return obj.str ();
465523 }
466524
467- inline std::string ToObjThree (const webifc::geometry::IfcGeometry& geom, size_t & offset, glm::dmat4 transform, double inputScale = 1.0 )
525+ inline std::string ToObjThree (const webifc::geometry::IfcGeometry& geom, size_t & offset, const glm::dmat4& transform, double inputScale = 1.0 )
468526 {
469527 std::stringstream obj;
470528 double scale = inputScale;
@@ -521,7 +579,8 @@ namespace webifc::dump
521579 {
522580 size_t offset = 0 ;
523581 std::ofstream out (path.c_str ());
524- out << ToObjThree (geom, offset, glm::dmat4 (1 ), inputScale);
582+ glm::dmat4 mat (1 );
583+ out << ToObjThree (geom, offset, mat, inputScale);
525584 }
526585
527586 inline std::string ToObjThree (webifc::geometry::IfcGeometry& geom, size_t & offset, glm::dmat4 transform = glm::dmat4(1 ))
@@ -548,17 +607,49 @@ namespace webifc::dump
548607 std::string complete;
549608 for (auto & geom : mesh.geometries )
550609 {
551- auto flatGeom = processor.GetGeometry (geom.geometryExpressID );
610+ webifc::geometry::IfcGeometry flatGeom = processor.GetGeometry (geom.geometryExpressID );
552611 glm::dmat4 trans = mat * geom.transformation ;
553612 complete += ToObjThree (flatGeom, offset, trans);
554613 }
555614 return complete;
556615 }
557616
558- inline void DumpIfcGeometryThree (webifc::geometry::IfcGeometry& geom, std::string filename)
617+ // Modified makeThreeJSViewer for IfcGeometry (triangle mesh)
618+ inline std::string makeThreeJSViewer (const std::vector<webifc::geometry::IfcGeometry>& vecGeom, double inputScale = 1.0 )
559619 {
620+ std::stringstream obj;
560621 size_t offset = 0 ;
561- writeFile (filename, ToObjThree (geom, offset));
622+ glm::dmat4 mat (1 );
623+ for (const webifc::geometry::IfcGeometry& geom : vecGeom)
624+ {
625+ obj << ToObjThree (geom, offset, mat, inputScale);
626+ }
627+
628+ // Escape OBJ data for embedding
629+ std::string objData = obj.str ();
630+ std::string escapedObjData;
631+ for (char c : objData)
632+ {
633+ if (c == ' \n ' ) escapedObjData += " \\ n" ;
634+ else if (c == ' "' ) escapedObjData += " \\\" " ;
635+ else escapedObjData += c;
636+ }
637+
638+ // Embed in HTML template
639+ std::string html = THREE_JS_VIEWER_TEMPLATE;
640+ size_t pos = html.find (R"( {})" );
641+ if (pos != std::string::npos)
642+ {
643+ html.replace (pos, 2 , escapedObjData);
644+ }
645+
646+ return html;
647+ }
648+
649+ inline void DumpIfcGeometryThree (std::vector<webifc::geometry::IfcGeometry> vecGeom, std::string filename, double epsNormal = 1e-8 , double epsDist = 1e-6 , double inputScale = 1.0 )
650+ {
651+ std::string viewer = makeThreeJSViewer (vecGeom, inputScale);
652+ writeFile (filename, viewer);
562653 }
563654
564655 inline void DumpFlatMeshThree (webifc::geometry::IfcFlatMesh& mesh, webifc::geometry::IfcGeometryProcessor& processor, std::string filename)
0 commit comments