bim export #246
This commit is contained in:
parent
4f627a7589
commit
267aeec79a
@ -1,4 +1,5 @@
|
||||
import { Exporter3dm } from './exporter3dm.js';
|
||||
import { ExporterBim } from './exporterbim.js';
|
||||
import { ExporterGltf } from './exportergltf.js';
|
||||
import { ExporterModel } from './exportermodel.js';
|
||||
import { ExporterObj } from './exporterobj.js';
|
||||
@ -16,7 +17,8 @@ export class Exporter
|
||||
new ExporterPly (),
|
||||
new ExporterOff (),
|
||||
new ExporterGltf (),
|
||||
new Exporter3dm ()
|
||||
new Exporter3dm (),
|
||||
new ExporterBim ()
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
77
source/engine/export/exporterbim.js
Normal file
77
source/engine/export/exporterbim.js
Normal file
@ -0,0 +1,77 @@
|
||||
import { FileFormat } from '../io/fileutils.js';
|
||||
import { ColorComponentFromFloat } from '../model/color.js';
|
||||
import { ConvertMeshToMeshBuffer } from '../model/meshbuffer.js';
|
||||
import { PropertyToString } from '../model/property.js';
|
||||
import { ExportedFile, ExporterBase } from './exporterbase.js';
|
||||
|
||||
export class ExporterBim extends ExporterBase
|
||||
{
|
||||
constructor ()
|
||||
{
|
||||
super ();
|
||||
}
|
||||
|
||||
CanExport (format, extension)
|
||||
{
|
||||
return format === FileFormat.Text && extension === 'bim';
|
||||
}
|
||||
|
||||
ExportContent (exporterModel, format, files, onFinish)
|
||||
{
|
||||
let bimContent = {
|
||||
schema_version : '1.0.0',
|
||||
meshes : [],
|
||||
elements : []
|
||||
};
|
||||
|
||||
this.ExportProperties (exporterModel.GetModel (), bimContent);
|
||||
|
||||
let meshId = 0;
|
||||
exporterModel.EnumerateTransformedMeshes ((mesh) => {
|
||||
let meshBuffer = ConvertMeshToMeshBuffer (mesh);
|
||||
for (let primitiveIndex = 0; primitiveIndex < meshBuffer.PrimitiveCount (); primitiveIndex++) {
|
||||
let primitive = meshBuffer.GetPrimitive (primitiveIndex);
|
||||
let material = exporterModel.GetMaterial (primitive.material);
|
||||
let bimMesh = {
|
||||
mesh_id : meshId,
|
||||
coordinates : primitive.vertices,
|
||||
indices : primitive.indices
|
||||
};
|
||||
let bimElement = {
|
||||
mesh_id : meshId,
|
||||
type : 'Other',
|
||||
color : {
|
||||
r : material.color.r,
|
||||
g : material.color.g,
|
||||
b : material.color.b,
|
||||
a : ColorComponentFromFloat (material.opacity)
|
||||
}
|
||||
};
|
||||
this.ExportProperties (mesh, bimElement);
|
||||
bimContent.meshes.push (bimMesh);
|
||||
bimContent.elements.push (bimElement);
|
||||
meshId += 1;
|
||||
}
|
||||
});
|
||||
|
||||
let bimFile = new ExportedFile ('model.bim');
|
||||
bimFile.SetTextContent (JSON.stringify (bimContent, null, 4));
|
||||
files.push (bimFile);
|
||||
onFinish ();
|
||||
}
|
||||
|
||||
ExportProperties (element, targetObject)
|
||||
{
|
||||
let info = {};
|
||||
for (let groupIndex = 0; groupIndex < element.PropertyGroupCount (); groupIndex++) {
|
||||
let group = element.GetPropertyGroup (groupIndex);
|
||||
for (let propertyIndex = 0; propertyIndex < group.PropertyCount (); propertyIndex++) {
|
||||
let property = group.GetProperty (propertyIndex);
|
||||
info[property.name] = PropertyToString (property);
|
||||
}
|
||||
}
|
||||
if (Object.keys (info).length !== 0) {
|
||||
targetObject.info = info;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -23,6 +23,11 @@ export class ExporterModel
|
||||
this.settings = settings || new ExporterSettings ();
|
||||
}
|
||||
|
||||
GetModel ()
|
||||
{
|
||||
return this.model;
|
||||
}
|
||||
|
||||
MaterialCount ()
|
||||
{
|
||||
return this.model.MaterialCount ();
|
||||
|
||||
@ -3,6 +3,7 @@ import { TaskRunner, RunTaskAsync, RunTasks, RunTasksBatch, WaitWhile } from './
|
||||
import { Exporter } from './export/exporter.js';
|
||||
import { Exporter3dm } from './export/exporter3dm.js';
|
||||
import { ExportedFile, ExporterBase } from './export/exporterbase.js';
|
||||
import { ExporterBim } from './export/exporterbim.js';
|
||||
import { ExporterGltf } from './export/exportergltf.js';
|
||||
import { ExporterSettings, ExporterModel } from './export/exportermodel.js';
|
||||
import { ExporterObj } from './export/exporterobj.js';
|
||||
@ -54,7 +55,7 @@ import { FinalizeModel, CheckModel } from './model/modelfinalization.js';
|
||||
import { IsModelEmpty, GetBoundingBox, GetTopology, IsSolid, HasDefaultMaterial, ReplaceDefaultMaterialColor } from './model/modelutils.js';
|
||||
import { Node, NodeType } from './model/node.js';
|
||||
import { Object3D, ModelObject3D } from './model/object.js';
|
||||
import { Property, PropertyGroup, PropertyType } from './model/property.js';
|
||||
import { Property, PropertyGroup, PropertyToString, PropertyType } from './model/property.js';
|
||||
import { GetTriangleArea, GetTetrahedronSignedVolume, CalculateVolume, CalculateSurfaceArea } from './model/quantities.js';
|
||||
import { TopologyVertex, TopologyEdge, TopologyTriangleEdge, TopologyTriangle, Topology } from './model/topology.js';
|
||||
import { Triangle } from './model/triangle.js';
|
||||
@ -82,6 +83,7 @@ export {
|
||||
Exporter3dm,
|
||||
ExportedFile,
|
||||
ExporterBase,
|
||||
ExporterBim,
|
||||
ExporterGltf,
|
||||
ExporterSettings,
|
||||
ExporterModel,
|
||||
@ -244,6 +246,7 @@ export {
|
||||
ModelObject3D,
|
||||
Property,
|
||||
PropertyGroup,
|
||||
PropertyToString,
|
||||
PropertyType,
|
||||
GetTriangleArea,
|
||||
GetTetrahedronSignedVolume,
|
||||
|
||||
@ -141,6 +141,7 @@ export class Mesh extends ModelObject3D
|
||||
let cloned = new Mesh ();
|
||||
|
||||
cloned.SetName (this.GetName ());
|
||||
this.CloneProperties (cloned);
|
||||
|
||||
for (let i = 0; i < this.VertexCount (); i++) {
|
||||
let vertex = this.GetVertex (i);
|
||||
|
||||
@ -80,4 +80,11 @@ export class ModelObject3D extends Object3D
|
||||
{
|
||||
return this.propertyGroups[index];
|
||||
}
|
||||
|
||||
CloneProperties (target)
|
||||
{
|
||||
for (let propertyGroup of this.propertyGroups) {
|
||||
target.AddPropertyGroup (propertyGroup.Clone ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { ColorToHexString } from './color.js';
|
||||
|
||||
export const PropertyType =
|
||||
{
|
||||
Text : 1,
|
||||
@ -16,6 +18,16 @@ export class Property
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
Clone ()
|
||||
{
|
||||
const clonable = (this.type === PropertyType.Color);
|
||||
if (clonable) {
|
||||
return new Property (this.type, this.name, this.value.Clone ());
|
||||
} else {
|
||||
return new Property (this.type, this.name, this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class PropertyGroup
|
||||
@ -40,4 +52,34 @@ export class PropertyGroup
|
||||
{
|
||||
return this.properties[index];
|
||||
}
|
||||
|
||||
Clone ()
|
||||
{
|
||||
let cloned = new PropertyGroup (this.name);
|
||||
for (let property of this.properties) {
|
||||
cloned.AddProperty (property.Clone ());
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
}
|
||||
|
||||
export function PropertyToString (property)
|
||||
{
|
||||
if (property.type === PropertyType.Text) {
|
||||
return property.value;
|
||||
} else if (property.type === PropertyType.Integer) {
|
||||
return property.value.toLocaleString ();
|
||||
} else if (property.type === PropertyType.Number) {
|
||||
return property.value.toLocaleString (undefined, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
});
|
||||
} else if (property.type === PropertyType.Boolean) {
|
||||
return property.value ? 'True' : 'False';
|
||||
} else if (property.type === PropertyType.Percent) {
|
||||
return parseInt (property.value * 100, 10).toString () + '%';
|
||||
} else if (property.type === PropertyType.Color) {
|
||||
return '#' + ColorToHexString (property.value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import { RunTaskAsync } from '../engine/core/taskrunner.js';
|
||||
import { SubCoord3D } from '../engine/geometry/coord3d.js';
|
||||
import { GetBoundingBox, IsSolid } from '../engine/model/modelutils.js';
|
||||
import { CalculateVolume, CalculateSurfaceArea } from '../engine/model/quantities.js';
|
||||
import { Property, PropertyType } from '../engine/model/property.js';
|
||||
import { Property, PropertyToString, PropertyType } from '../engine/model/property.js';
|
||||
import { AddDiv, AddDomElement, ClearDomElement } from '../engine/viewer/domutils.js';
|
||||
import { SidebarPanel } from './sidebarpanel.js';
|
||||
import { CreateInlineColorCircle } from './utils.js';
|
||||
@ -164,24 +164,15 @@ export class SidebarDetailsPanel extends SidebarPanel
|
||||
valueHtml = '<a target="_blank" href="' + property.value + '">' + property.value + '</a>';
|
||||
valueTitle = property.value;
|
||||
} else {
|
||||
valueHtml = property.value;
|
||||
valueHtml = PropertyToString (property);
|
||||
}
|
||||
} else if (property.type === PropertyType.Integer) {
|
||||
valueHtml = property.value.toLocaleString ();
|
||||
} else if (property.type === PropertyType.Number) {
|
||||
valueHtml = property.value.toLocaleString (undefined, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
});
|
||||
} else if (property.type === PropertyType.Boolean) {
|
||||
valueHtml = property.value ? 'True' : 'False';
|
||||
} else if (property.type === PropertyType.Percent) {
|
||||
valueHtml = parseInt (property.value * 100, 10).toString () + '%';
|
||||
} else if (property.type === PropertyType.Color) {
|
||||
let hexString = '#' + ColorToHexString (property.value);
|
||||
let colorCircle = CreateInlineColorCircle (property.value);
|
||||
targetDiv.appendChild (colorCircle);
|
||||
AddDomElement (targetDiv, 'span', null, hexString);
|
||||
} else {
|
||||
valueHtml = PropertyToString (property);
|
||||
}
|
||||
if (valueHtml !== null) {
|
||||
targetDiv.innerHTML = valueHtml;
|
||||
|
||||
@ -133,16 +133,20 @@ function ExportImport (model, format, extension, onReady)
|
||||
});
|
||||
}
|
||||
|
||||
function CheckModelBounds (model, model2)
|
||||
{
|
||||
let modelBounds = OV.GetBoundingBox (model);
|
||||
let model2Bounds = OV.GetBoundingBox (model2);
|
||||
assert.ok (OV.CoordIsEqual3D (modelBounds.min, model2Bounds.min));
|
||||
assert.ok (OV.CoordIsEqual3D (modelBounds.max, model2Bounds.max));
|
||||
}
|
||||
|
||||
function CheckSingleMeshModel (model, model2)
|
||||
{
|
||||
assert.strictEqual (model2.MaterialCount (), 1);
|
||||
assert.strictEqual (model2.MeshInstanceCount (), 1);
|
||||
assert.strictEqual (model.TriangleCount (), model2.TriangleCount ());
|
||||
|
||||
let modelBounds = OV.GetBoundingBox (model);
|
||||
let model2Bounds = OV.GetBoundingBox (model2);
|
||||
assert.ok (OV.CoordIsEqual3D (modelBounds.min, model2Bounds.min));
|
||||
assert.ok (OV.CoordIsEqual3D (modelBounds.max, model2Bounds.max));
|
||||
CheckModelBounds (model, model2);
|
||||
}
|
||||
|
||||
function CheckModel (model, model2)
|
||||
@ -150,11 +154,7 @@ function CheckModel (model, model2)
|
||||
assert.strictEqual (model.MaterialCount (), model2.MaterialCount ());
|
||||
assert.strictEqual (model.MeshInstanceCount (), model2.MeshInstanceCount ());
|
||||
assert.strictEqual (model.TriangleCount (), model2.TriangleCount ());
|
||||
|
||||
let modelBounds = OV.GetBoundingBox (model);
|
||||
let model2Bounds = OV.GetBoundingBox (model2);
|
||||
assert.ok (OV.CoordIsEqual3D (modelBounds.min, model2Bounds.min));
|
||||
assert.ok (OV.CoordIsEqual3D (modelBounds.max, model2Bounds.max));
|
||||
CheckModelBounds (model, model2);
|
||||
}
|
||||
|
||||
describe ('Export-Import Test', function () {
|
||||
@ -221,6 +221,17 @@ describe ('Export-Import Test', function () {
|
||||
done ();
|
||||
});
|
||||
});
|
||||
|
||||
it ('Export-Import Bim', function (done) {
|
||||
let model = CreateTestModel ();
|
||||
ExportImport (model, OV.FileFormat.Text, 'bim', (model2) => {
|
||||
assert.strictEqual (model2.MaterialCount (), 2);
|
||||
assert.strictEqual (model.MeshInstanceCount (), model2.MeshInstanceCount ());
|
||||
assert.strictEqual (model.TriangleCount (), model2.TriangleCount ());
|
||||
CheckModelBounds (model, model2);
|
||||
done ();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe ('Export-Import Vertex Colors Test', function () {
|
||||
|
||||
@ -5,7 +5,7 @@ export default function suite ()
|
||||
{
|
||||
|
||||
describe ('Property Test', function () {
|
||||
it ('Property Group', function() {
|
||||
it ('Property group', function() {
|
||||
let group = new OV.PropertyGroup ('Group');
|
||||
group.AddProperty (new OV.Property (OV.PropertyType.Text, 'name 01', 'value 01'));
|
||||
group.AddProperty (new OV.Property (OV.PropertyType.Integer, 'name 02', 2));
|
||||
@ -19,7 +19,7 @@ describe ('Property Test', function () {
|
||||
assert.strictEqual (group.GetProperty (2).value, 3.5);
|
||||
});
|
||||
|
||||
it ('Model Properties', function() {
|
||||
it ('Model properties', function() {
|
||||
let model = new OV.Model ();
|
||||
let group1 = new OV.PropertyGroup ('Group 01');
|
||||
let group2 = new OV.PropertyGroup ('Group 02');
|
||||
@ -41,6 +41,69 @@ describe ('Property Test', function () {
|
||||
assert.strictEqual (model.GetPropertyGroup (2).GetProperty (0).name, 'name 03');
|
||||
assert.strictEqual (model.GetPropertyGroup (2).GetProperty (0).value, 3.5);
|
||||
});
|
||||
|
||||
it ('Mesh properties', function() {
|
||||
let mesh = new OV.Mesh ();
|
||||
let group1 = new OV.PropertyGroup ('Group 01');
|
||||
let group2 = new OV.PropertyGroup ('Group 02');
|
||||
let group3 = new OV.PropertyGroup ('Group 03');
|
||||
group1.AddProperty (new OV.Property (OV.PropertyType.Text, 'name 01', 'value 01'));
|
||||
group2.AddProperty (new OV.Property (OV.PropertyType.Integer, 'name 02', 2));
|
||||
group3.AddProperty (new OV.Property (OV.PropertyType.Number, 'name 03', 3.5));
|
||||
mesh.AddPropertyGroup (group1);
|
||||
mesh.AddPropertyGroup (group2);
|
||||
mesh.AddPropertyGroup (group3);
|
||||
assert.strictEqual (mesh.PropertyGroupCount (), 3);
|
||||
assert.strictEqual (mesh.GetPropertyGroup (0).name, 'Group 01');
|
||||
assert.strictEqual (mesh.GetPropertyGroup (1).name, 'Group 02');
|
||||
assert.strictEqual (mesh.GetPropertyGroup (2).name, 'Group 03');
|
||||
assert.strictEqual (mesh.GetPropertyGroup (0).GetProperty (0).name, 'name 01');
|
||||
assert.strictEqual (mesh.GetPropertyGroup (0).GetProperty (0).value, 'value 01');
|
||||
assert.strictEqual (mesh.GetPropertyGroup (1).GetProperty (0).name, 'name 02');
|
||||
assert.strictEqual (mesh.GetPropertyGroup (1).GetProperty (0).value, 2);
|
||||
assert.strictEqual (mesh.GetPropertyGroup (2).GetProperty (0).name, 'name 03');
|
||||
assert.strictEqual (mesh.GetPropertyGroup (2).GetProperty (0).value, 3.5);
|
||||
});
|
||||
|
||||
it ('Mesh clone test', function() {
|
||||
let mesh = new OV.Mesh ();
|
||||
let group1 = new OV.PropertyGroup ('Group 01');
|
||||
let group2 = new OV.PropertyGroup ('Group 02');
|
||||
let group3 = new OV.PropertyGroup ('Group 03');
|
||||
group1.AddProperty (new OV.Property (OV.PropertyType.Text, 'name 01', 'value 01'));
|
||||
group2.AddProperty (new OV.Property (OV.PropertyType.Integer, 'name 02', 2));
|
||||
group3.AddProperty (new OV.Property (OV.PropertyType.Number, 'name 03', 3.5));
|
||||
group3.AddProperty (new OV.Property (OV.PropertyType.Color, 'name 04', new OV.Color (10, 20, 30)));
|
||||
mesh.AddPropertyGroup (group1);
|
||||
mesh.AddPropertyGroup (group2);
|
||||
mesh.AddPropertyGroup (group3);
|
||||
let cloned = mesh.Clone ();
|
||||
assert.strictEqual (cloned.PropertyGroupCount (), 3);
|
||||
assert.strictEqual (cloned.GetPropertyGroup (0).name, 'Group 01');
|
||||
assert.strictEqual (cloned.GetPropertyGroup (1).name, 'Group 02');
|
||||
assert.strictEqual (cloned.GetPropertyGroup (2).name, 'Group 03');
|
||||
assert.strictEqual (cloned.GetPropertyGroup (0).GetProperty (0).name, 'name 01');
|
||||
assert.strictEqual (cloned.GetPropertyGroup (0).GetProperty (0).value, 'value 01');
|
||||
assert.strictEqual (cloned.GetPropertyGroup (1).GetProperty (0).name, 'name 02');
|
||||
assert.strictEqual (cloned.GetPropertyGroup (1).GetProperty (0).value, 2);
|
||||
assert.strictEqual (cloned.GetPropertyGroup (2).GetProperty (0).name, 'name 03');
|
||||
assert.strictEqual (cloned.GetPropertyGroup (2).GetProperty (0).value, 3.5);
|
||||
assert.strictEqual (cloned.GetPropertyGroup (2).GetProperty (1).name, 'name 04');
|
||||
assert.strictEqual (
|
||||
OV.ColorToHexString (cloned.GetPropertyGroup (2).GetProperty (1).value),
|
||||
OV.ColorToHexString (new OV.Color (10, 20, 30))
|
||||
);
|
||||
});
|
||||
|
||||
it ('Property to string', function() {
|
||||
assert.strictEqual (OV.PropertyToString (new OV.Property (OV.PropertyType.Text, 'name', 'test')), 'test');
|
||||
assert.strictEqual (OV.PropertyToString (new OV.Property (OV.PropertyType.Integer, 'name', 42)), '42');
|
||||
assert.strictEqual (OV.PropertyToString (new OV.Property (OV.PropertyType.Number, 'name', 3.14)), '3.14');
|
||||
assert.strictEqual (OV.PropertyToString (new OV.Property (OV.PropertyType.Boolean, 'name', true)), 'True');
|
||||
assert.strictEqual (OV.PropertyToString (new OV.Property (OV.PropertyType.Boolean, 'name', false)), 'False');
|
||||
assert.strictEqual (OV.PropertyToString (new OV.Property (OV.PropertyType.Percent, 'name', 0.2)), '20%');
|
||||
assert.strictEqual (OV.PropertyToString (new OV.Property (OV.PropertyType.Color, 'color', new OV.Color (10, 20, 20))), '#0a1414');
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@
|
||||
<td>bim</td>
|
||||
<td>text</td>
|
||||
<td class="center green">✓</td>
|
||||
<td class="center red">✗</td>
|
||||
<td class="center green">✓</td>
|
||||
<td>Native</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user