Skip to content

Commit

Permalink
Merge branch 'improve-fragment' into big-restructure
Browse files Browse the repository at this point in the history
  • Loading branch information
agviegas committed Jun 29, 2023
2 parents 445535c + 6e8d9e9 commit d84e47c
Show file tree
Hide file tree
Showing 39 changed files with 1,909 additions and 2,230 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
},
"dependencies": {
"@popperjs/core": "latest",
"bim-fragment": "0.0.21",
"bim-fragment": "1.0.7",
"camera-controls": "^1.36.0",
"dexie": "^3.2.3",
"mapbox-gl": "^2.15.0",
Expand Down
1,806 changes: 883 additions & 923 deletions resources/openbim-components.js

Large diffs are not rendered by default.

Binary file modified resources/small.frag
Binary file not shown.
1 change: 1 addition & 0 deletions resources/small.json

Large diffs are not rendered by default.

Binary file removed resources/small.zip
Binary file not shown.
4 changes: 4 additions & 0 deletions resources/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,10 @@ select {
top: 2rem;
}

.isolate {
isolation: isolate;
}

.z-10 {
z-index: 10;
}
Expand Down
22 changes: 4 additions & 18 deletions src/fragments/FragmentCacher/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as THREE from "three";
import { FragmentsGroup } from "bim-fragment";
import { LocalCacher } from "../../core";
import { FragmentGroup } from "../FragmentIfcLoader";
import { FragmentManager } from "../FragmentManager";

export class FragmentCacher extends LocalCacher {
Expand Down Expand Up @@ -42,33 +42,19 @@ export class FragmentCacher extends LocalCacher {
return loadedModel;
}

async saveFragmentGroup(group: FragmentGroup, id: string) {
async saveFragmentGroup(group: FragmentsGroup, id: string) {
const fragments = new FragmentManager(this.components);
for (const fragment of group.fragments) {
fragments.list[fragment.id] = fragment;
}

const { fragmentsCacheID, propertiesCacheID } = this.getIDs(id);

const exported = fragments.export();
const exported = fragments.export(group);
const fragmentsFile = this.newFile(exported, fragmentsCacheID);
const fragmentsUrl = URL.createObjectURL(fragmentsFile);
await this.save(fragmentsCacheID, fragmentsUrl);

const { properties, itemTypes, allTypes, expressIDFragmentIDMap } = group;

const data = {
properties,
itemTypes,
allTypes,
expressIDFragmentIDMap,
};

const json = JSON.stringify(data);
const json = JSON.stringify(group.properties);
const jsonFile = this.newFile(json, propertiesCacheID);
const propertiesUrl = URL.createObjectURL(jsonFile);
await this.save(propertiesCacheID, propertiesUrl);
fragments.list = {};
}

private getIDs(id: string) {
Expand Down
212 changes: 212 additions & 0 deletions src/fragments/FragmentClassifier/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import { FragmentsGroup } from "bim-fragment";
import { Disposable } from "../../base-types";
import { Component } from "../../base-types/component";
import { FragmentManager } from "../FragmentManager";
import { IfcCategoryMap } from "../../ifc";

// TODO: Clean up and document

export interface Classification {
[system: string]: {
[className: string]: { [fragmentID: string]: Set<string> };
};
}

export class FragmentClassifier
extends Component<Classification>
implements Disposable
{
/** {@link Component.name} */
name = "FragmentClassifier";

/** {@link Component.enabled} */
enabled = true;

private _groupSystems: Classification = {};
private _fragments: FragmentManager;

constructor(fragmentManager: FragmentManager) {
super();
this._fragments = fragmentManager;
}

/** {@link Component.get} */
get(): Classification {
return this._groupSystems;
}

dispose() {
this._groupSystems = {};
}

remove(guid: string) {
for (const systemName in this._groupSystems) {
const system = this._groupSystems[systemName];
for (const groupName in system) {
const group = system[groupName];
delete group[guid];
}
}
}

find(filter?: { [name: string]: string }) {
if (!filter) {
const result: { [p: string]: string[] } = {};
const fragments = this._fragments.list;
for (const id in fragments) {
const fragment = fragments[id];
const items = fragment.items;
const hidden = Object.keys(fragment.hiddenInstances);
result[id] = [...items, ...hidden];
}
return result;
}
const size = Object.keys(filter).length;
const models: { [fragmentGuid: string]: { [id: string]: number } } = {};
for (const name in filter) {
const value = filter[name];
if (!this._groupSystems[name]) {
console.warn(`Classification ${name} does not exist.`);
continue;
}
const found = this._groupSystems[name][value];
if (found) {
for (const guid in found) {
if (!models[guid]) {
models[guid] = {};
}
for (const id of found[guid]) {
if (!models[guid][id]) {
models[guid][id] = 1;
} else {
models[guid][id]++;
}
}
}
}
}
const result: { [fragmentGuid: string]: string[] } = {};
for (const guid in models) {
const model = models[guid];
for (const id in model) {
const numberOfMatches = model[id];
if (numberOfMatches === size) {
if (!result[guid]) {
result[guid] = [];
}
result[guid].push(id);
}
}
}
return result;
}

byModel(modelID: string, group: FragmentsGroup) {
if (!this._groupSystems.model) {
this._groupSystems.model = {};
}
const modelsClassification = this._groupSystems.model;
if (!modelsClassification[modelID]) {
modelsClassification[modelID] = {};
}
const currentModel = modelsClassification[modelID];
for (const expressID in group.data) {
const keys = group.data[expressID][0];
for (const key of keys) {
const fragID = group.keyFragments[key];
if (!currentModel[fragID]) {
currentModel[fragID] = new Set<string>();
}
currentModel[fragID].add(expressID);
}
}
}

byPredefinedType(group: FragmentsGroup) {
if (!group.properties) {
throw new Error("To group by predefined type, properties are needed");
}

if (!this._groupSystems.predefinedTypes) {
this._groupSystems.predefinedTypes = {};
}

const currentTypes = this._groupSystems.predefinedTypes;

for (const expressID in group.data) {
const entity = group.properties[expressID];
if (!entity) continue;

const predefinedType = String(entity.PredefinedType?.value).toUpperCase();

if (!currentTypes[predefinedType]) {
currentTypes[predefinedType] = {};
}
const currentType = currentTypes[predefinedType];

for (const expressID in group.data) {
const keys = group.data[expressID][0];
for (const key of keys) {
const fragmentID = group.keyFragments[key];
if (!currentType[fragmentID]) {
currentType[fragmentID] = new Set<string>();
}
const currentFragment = currentType[fragmentID];
currentFragment.add(entity.expressID);
}
}
}
}

byEntity(group: FragmentsGroup) {
if (!this._groupSystems.entities) {
this._groupSystems.entities = {};
}

for (const expressID in group.data) {
const rels = group.data[expressID][1];
const type = rels[1];
const entity = IfcCategoryMap[type];
this.saveItem(group, "entities", entity, expressID);
}
}

byStorey(group: FragmentsGroup) {
if (!group.properties) {
throw new Error("To group by storey, properties are needed");
}

for (const expressID in group.data) {
const rels = group.data[expressID][1];
const storeyID = rels[0];
if (storeyID === -1) continue;
const storey = group.properties[storeyID].Name.value;
this.saveItem(group, "storeys", storey, expressID);
}
}

private saveItem(
group: FragmentsGroup,
systemName: string,
className: string,
expressID: string
) {
if (!this._groupSystems[systemName]) {
this._groupSystems[systemName] = {};
}
const keys = group.data[expressID as any][0];
for (const key of keys) {
const fragmentID = group.keyFragments[key];
if (fragmentID) {
const system = this._groupSystems[systemName];
if (!system[className]) {
system[className] = {};
}
if (!system[className][fragmentID]) {
system[className][fragmentID] = new Set<string>();
}
system[className][fragmentID].add(expressID);
}
}
}
}
8 changes: 3 additions & 5 deletions src/fragments/FragmentEdges/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,12 @@
const file = await fetch("../../../resources/small.frag");
const data = await file.arrayBuffer();
const buffer = new Uint8Array(data);
const ids = fragments.load(buffer);

const edges = new OBC.FragmentEdges(components);
const model = fragments.load(buffer);

const culler = new OBC.ScreenCuller(components);
const edges = new OBC.FragmentEdges(components, culler);

for(const id of ids) {
const fragment = fragments.list[id];
for(const fragment of model.items) {
edges.add(fragment);
culler.add(fragment.mesh);
}
Expand Down
20 changes: 18 additions & 2 deletions src/fragments/FragmentEdges/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "three";
import { Fragment } from "bim-fragment";
import { Disposable, Component, Hideable } from "../../base-types";
import { Components, Disposer } from "../../core";
import { Components, Disposer, ScreenCuller } from "../../core";

// TODO: Clean up and document
// TODO: Decouple from fragments?
Expand Down Expand Up @@ -78,9 +78,25 @@ export class FragmentEdges
}
}

constructor(components: Components) {
constructor(components: Components, culler?: ScreenCuller) {
super();
this._components = components;
if (culler) {
culler.viewUpdated.on(() => {
const scene = this._components.scene.get();
if (!this.visible) return;
for (const id of culler.currentVisibleMeshes) {
if (this._list[id]) {
scene.add(this._list[id]);
}
}
for (const id of culler.recentlyHiddenMeshes) {
if (this._list[id]) {
scene.remove(this._list[id]);
}
}
});
}
}

get() {
Expand Down
Loading

0 comments on commit d84e47c

Please sign in to comment.