Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions packages/core/src/openbim/IDSSpecifications/src/facets/Property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ export class IDSProperty extends IDSFacet {
// Matching sets, by localId: their name and the property names that
// matched. A set attached to a type (IfcTypeObject.HasPropertySets)
// has no DefinesOccurrence, so its elements are found from the type.
const matchedSets = new Map<number, { name: string; props: Set<string> }>();
const matchedSets = new Map<
number,
{ name: string; props: Set<string> }
>();

for (const set of data) {
const definesOccurrence = set.DefinesOccurrence ?? set.DefinesOcurrence;
Expand Down Expand Up @@ -220,7 +223,8 @@ export class IDSProperty extends IDSFacet {
for (const type of types) {
if (!Array.isArray(type.HasPropertySets)) continue;
const sets = type.HasPropertySets.flatMap((set) => {
const id = set._localId && "value" in set._localId ? set._localId.value : null;
const id =
set._localId && "value" in set._localId ? set._localId.value : null;
const matched = matchedSets.get(id as number);
return matched ? [matched] : [];
});
Expand Down Expand Up @@ -260,12 +264,15 @@ export class IDSProperty extends IDSFacet {
const props = list ? set[list] : undefined;
if (!Array.isArray(props)) return false;
return props.some(
(prop) => prop.Name && "value" in prop.Name && prop.Name.value === propName,
(prop) =>
prop.Name && "value" in prop.Name && prop.Name.value === propName,
);
});
const inherits = inherited
.get(id)!
.some((set) => [...set.props].some((prop) => !overrides(set.name, prop)));
.some((set) =>
[...set.props].some((prop) => !overrides(set.name, prop)),
);
if (inherits) applies.push(id);
}
ModelIdMapUtils.append(collector, modelId, ...applies);
Expand Down Expand Up @@ -422,6 +429,12 @@ export class IDSProperty extends IDSFacet {
}
}

// When the item is itself a type object (e.g. an IfcWallType selected by
// the applicability), its own property sets are in HasPropertySets.
if (Array.isArray(item.HasPropertySets)) {
psets.push(...item.HasPropertySets);
}

return psets;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import * as FRAGS from "@thatopen/fragments";
import * as fs from "fs";
import * as path from "path";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import type { Components } from "../../../../index";
import { loadSourceBundle } from "../../../../../tests/source-bundle";

// Needs the real `Components`: see `loadSourceBundle`.
const OBC = await loadSourceBundle();

const MODEL_ID = "type-psets";

// `tests/fixtures/type-psets.ifc` (see property.test.ts): IfcWallType #52
// carries Pset_WallCommon.IsExternal = TRUE in its HasPropertySets.
const WALL_TYPE = 52;

const convert = async () => {
const importer = new FRAGS.IfcImporter();
const root = path.resolve(__dirname, "../../../../..");
importer.wasm = {
path: `${path.resolve(root, "../../node_modules/web-ifc")}/`,
absolute: true,
};
const ifc = fs.readFileSync(
path.join(root, "tests", "fixtures", "type-psets.ifc"),
);
const bytes = await importer.process({
bytes: new Uint8Array(ifc),
raw: true,
});
return new FRAGS.SingleThreadedFragmentsModel(MODEL_ID, bytes, true);
};

describe("IDSProperty on a type object", () => {
let components: Components;
let model: FRAGS.SingleThreadedFragmentsModel;

beforeAll(async () => {
model = await convert();
components = new OBC.Components();
const fragments = components.get(OBC.FragmentsManager);
vi.spyOn(fragments, "list", "get").mockReturnValue(
new Map([[MODEL_ID, model]]) as never,
);
}, 60_000);

afterAll(() => {
vi.restoreAllMocks();
components?.dispose();
model?.dispose();
});

it("checks the type object's own property sets", async () => {
const spec = components
.get(OBC.IDSSpecifications)
.create("wall types are external", ["IFC4"]);
spec.applicability.add(
new OBC.IDSEntity(components, {
type: "simple",
parameter: "IFCWALLTYPE",
}),
);
const property = new OBC.IDSProperty(
components,
{ type: "simple", parameter: "Pset_WallCommon" },
{ type: "simple", parameter: "IsExternal" },
);
property.value = { type: "simple", parameter: true };
spec.requirements.add(property);

const result = await spec.test([new RegExp(MODEL_ID)]);
const typeResult = result.get(MODEL_ID)?.get(WALL_TYPE);
expect(typeResult?.pass).toBe(true);
});
});
Loading