Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(react-components): add support for system data models to react components #3569

Merged
merged 14 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
type CogniteCadModel,
TreeIndexNodeCollection,
NodeIdNodeCollection,
DefaultNodeAppearance
DefaultNodeAppearance,
type NodeCollection
} from '@cognite/reveal';
import { useReveal } from '../RevealContainer/RevealContext';
import { Matrix4 } from 'three';
Expand Down Expand Up @@ -46,9 +47,13 @@ export function CadModelContainer({
}: CogniteCadModelProps): ReactElement {
const cachedViewerRef = useRevealKeepAlive();
const [model, setModel] = useState<CogniteCadModel>();

const viewer = useReveal();
const sdk = useSDK();

const defaultStyle = styling?.defaultStyle ?? DefaultNodeAppearance.Default;
const styleGroups = styling?.groups;

const { modelId, revisionId, geometryFilter } = addModelOptions;

useEffect(() => {
Expand All @@ -61,15 +66,28 @@ export function CadModelContainer({
}, [transform, model]);

useEffect(() => {
if (model === undefined || styling === undefined) return;
if (model === undefined || styleGroups === undefined) return;
const stylingCollections = applyStyling(sdk, model, styleGroups);

applyStyling(sdk, model, styling).catch(console.error);
return () => {
if (model === undefined) return;
void stylingCollections.then((nodeCollections) => {
nodeCollections.forEach((nodeCollection) => {
model.unassignStyledNodeCollection(nodeCollection);
});
});
};
}, [styleGroups, model]);

useEffect(() => {
if (model === undefined) return;
model.setDefaultNodeAppearance(defaultStyle);
return () => {
model.removeAllStyledNodeCollections();
model.setDefaultNodeAppearance(DefaultNodeAppearance.Default);
if (model !== undefined) {
model.setDefaultNodeAppearance(DefaultNodeAppearance.Default);
}
};
}, [styling, model]);
}, [defaultStyle, model]);

useEffect(() => removeModel, [model]);

Expand Down Expand Up @@ -118,24 +136,20 @@ export function CadModelContainer({
async function applyStyling(
sdk: CogniteClient,
model: CogniteCadModel,
styling?: CadModelStyling
): Promise<void> {
if (styling === undefined) return;

if (styling.defaultStyle !== undefined) {
model.setDefaultNodeAppearance(styling.defaultStyle);
}

if (styling.groups !== undefined) {
for (const group of styling.groups) {
if ('treeIndices' in group && group.style !== undefined) {
const nodes = new TreeIndexNodeCollection(group.treeIndices);
model.assignStyledNodeCollection(nodes, group.style);
} else if ('nodeIds' in group && group.style !== undefined) {
const nodes = new NodeIdNodeCollection(sdk, model);
await nodes.executeFilter(group.nodeIds);
model.assignStyledNodeCollection(nodes, group.style);
}
stylingGroups: Array<NodeStylingGroup | TreeIndexStylingGroup>
): Promise<NodeCollection[]> {
const collections: NodeCollection[] = [];
for (const group of stylingGroups) {
if ('treeIndices' in group && group.style !== undefined) {
const nodes = new TreeIndexNodeCollection(group.treeIndices);
model.assignStyledNodeCollection(nodes, group.style);
collections.push(nodes);
} else if ('nodeIds' in group && group.style !== undefined) {
const nodes = new NodeIdNodeCollection(sdk, model);
await nodes.executeFilter(group.nodeIds);
model.assignStyledNodeCollection(nodes, group.style);
collections.push(nodes);
}
}
return collections;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@
* Copyright 2023 Cognite AS
*/
import { useRef, type ReactElement, useContext, useState, useEffect } from 'react';
import {
type NodeAppearance,
type Cognite3DViewer,
type PointCloudAppearance,
type PointerEventData
} from '@cognite/reveal';
import { type NodeAppearance, type Cognite3DViewer, type PointerEventData } from '@cognite/reveal';
import { ModelsLoadingStateContext } from './ModelsLoadingContext';
import { CadModelContainer, type CadModelStyling } from '../CadModelContainer/CadModelContainer';
import {
Expand All @@ -23,39 +18,28 @@ import {
type AddResourceOptions,
type NodeDataResult
} from './types';
import { type CogniteExternalId } from '@cognite/sdk';
import { type FdmAssetMappingsConfig } from '../../hooks/types';
import { useCalculateModelsStyling } from '../../hooks/useCalculateModelsStyling';
import { queryMappedData } from './queryMappedData';
import { useFdmSdk, useSDK } from '../RevealContainer/SDKProvider';
import { useCalculateModelsStyling2 } from '../../hooks/useCalculateModelsStyling';
import { type DmsUniqueIdentifier } from '../../utilities/FdmSDK';

export type FdmAssetStylingGroup = {
fdmAssetExternalIds: CogniteExternalId[];
style: { cad?: NodeAppearance; pointcloud?: PointCloudAppearance };
};

export type Reveal3DResourcesStyling = {
defaultStyle?: { cad?: NodeAppearance; pointcloud?: PointCloudAppearance };
groups?: FdmAssetStylingGroup[];
fdmAssetExternalIds: DmsUniqueIdentifier[];
style: { cad: NodeAppearance };
};

export type Reveal3DResourcesProps = {
resources: AddResourceOptions[];
fdmAssetMappingConfig?: FdmAssetMappingsConfig;
styling?: Reveal3DResourcesStyling;
instanceStyling?: FdmAssetStylingGroup[];
onNodeClick?: (node: Promise<NodeDataResult | undefined>) => void;
};

export const Reveal3DResources = ({
resources,
styling,
fdmAssetMappingConfig,
instanceStyling,
onNodeClick
}: Reveal3DResourcesProps): ReactElement => {
const [reveal3DModels, setReveal3DModels] = useState<TypedReveal3DModel[]>([]);
const [reveal3DModelsStyling, setReveal3DModelsStyling] = useState<
Array<PointCloudModelStyling | CadModelStyling>
>([]);

const { setModelsAdded } = useContext(ModelsLoadingStateContext);
const viewer = useReveal();
Expand All @@ -67,16 +51,12 @@ export const Reveal3DResources = ({
getTypedModels(resources, viewer).then(setReveal3DModels).catch(console.error);
}, [resources, viewer]);

const modelsStyling = useCalculateModelsStyling(reveal3DModels, styling, fdmAssetMappingConfig);

useEffect(() => {
setReveal3DModelsStyling(modelsStyling);
}, [modelsStyling]);
const reveal3DModelsStyling = useCalculateModelsStyling2(reveal3DModels, instanceStyling ?? []);

useEffect(() => {
const callback = (event: PointerEventData): void => {
if (onNodeClick === undefined) return;
const data = queryMappedData(viewer, client, fdmSdk, event, fdmAssetMappingConfig);
const data = queryMappedData(viewer, client, fdmSdk, event);
onNodeClick(data);
};

Expand All @@ -85,7 +65,7 @@ export const Reveal3DResources = ({
return () => {
viewer.off('click', callback);
};
}, [viewer, client, fdmSdk, fdmAssetMappingConfig, onNodeClick]);
}, [viewer, client, fdmSdk, onNodeClick]);

const image360CollectionAddOptions = resources.filter(
(resource): resource is AddImageCollection360Options =>
Expand Down Expand Up @@ -165,6 +145,11 @@ async function getTypedModels(
addModelOptions.modelId,
addModelOptions.revisionId
);
if (type === '') {
throw new Error(
`Could not determine model type for modelId: ${addModelOptions.modelId} and revisionId: ${addModelOptions.revisionId}`
);
}
const typedModel: TypedReveal3DModel = { ...addModelOptions, type };
return typedModel;
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,20 @@ import {
type FdmSDK,
type DmsUniqueIdentifier
} from '../../utilities/FdmSDK';
import { type FdmAssetMappingsConfig } from '../../hooks/types';
import { type NodeDataResult } from './types';
import assert from 'assert';
import {
INSTANCE_SPACE_3D_DATA,
type InModel3dEdgeProperties,
SYSTEM_3D_EDGE_SOURCE
} from '../../utilities/globalDataModels';

export async function queryMappedData(
viewer: Cognite3DViewer,
cdfClient: CogniteClient,
fdmClient: FdmSDK,
clickEvent: PointerEventData,
fdmConfig?: FdmAssetMappingsConfig
clickEvent: PointerEventData
): Promise<NodeDataResult | undefined> {
if (fdmConfig === undefined) {
throw Error('Must supply fdmConfig when using FDM queries');
}

const intersection = await viewer.getIntersectionFromPixel(
clickEvent.offsetX,
clickEvent.offsetY
Expand All @@ -41,7 +40,6 @@ export async function queryMappedData(

const mappings = await getMappingEdges(
fdmClient,
fdmConfig,
model,
ancestors.map((n) => n.id)
);
Expand All @@ -51,10 +49,7 @@ export async function queryMappedData(
}

const selectedEdge = mappings.edges[0];
const selectedNodeId =
selectedEdge.properties[fdmConfig.source.space][
`${fdmConfig.source.externalId}/${fdmConfig.source.version}`
].revisionNodeId;
const selectedNodeId = selectedEdge.properties.revisionNodeId;
const selectedNode = ancestors.find((n) => n.id === selectedNodeId);
assert(selectedNode !== undefined);

Expand Down Expand Up @@ -91,26 +86,25 @@ async function getAncestorNodesForTreeIndex(

async function getMappingEdges(
fdmClient: FdmSDK,
fdmConfig: FdmAssetMappingsConfig,
model: CogniteCadModel,
ancestorIds: CogniteInternalId[]
): Promise<{ edges: Array<EdgeItem<Record<string, any>>> }> {
): Promise<{ edges: Array<EdgeItem<InModel3dEdgeProperties>> }> {
const filter = {
and: [
{
equals: {
property: ['edge', 'endNode'],
value: {
space: fdmConfig.global3dSpace,
externalId: `model_3d_${model.modelId}`
space: INSTANCE_SPACE_3D_DATA,
externalId: `${model.modelId}`
christjt marked this conversation as resolved.
Show resolved Hide resolved
}
}
},
{
equals: {
property: [
fdmConfig.source.space,
`${fdmConfig.source.externalId}/${fdmConfig.source.version}`,
SYSTEM_3D_EDGE_SOURCE.space,
`${SYSTEM_3D_EDGE_SOURCE.externalId}/${SYSTEM_3D_EDGE_SOURCE.version}`,
'revisionId'
],
value: model.revisionId
Expand All @@ -119,8 +113,8 @@ async function getMappingEdges(
{
in: {
property: [
fdmConfig.source.space,
`${fdmConfig.source.externalId}/${fdmConfig.source.version}`,
SYSTEM_3D_EDGE_SOURCE.space,
`${SYSTEM_3D_EDGE_SOURCE.externalId}/${SYSTEM_3D_EDGE_SOURCE.version}`,
'revisionNodeId'
],
values: ancestorIds
Expand All @@ -129,7 +123,11 @@ async function getMappingEdges(
]
};

return await fdmClient.filterAllInstances(filter, 'edge', fdmConfig.source);
return await fdmClient.filterAllInstances<InModel3dEdgeProperties>(
filter,
'edge',
SYSTEM_3D_EDGE_SOURCE
);
}

async function inspectNode(
Expand Down
9 changes: 6 additions & 3 deletions react-components/src/components/Reveal3DResources/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import {
type AddModelOptions,
type SupportedModelTypes,
type CadIntersection
type CadIntersection,
type NodeAppearance
} from '@cognite/reveal';
import { type Matrix4 } from 'three';
import { type Source } from '../../utilities/FdmSDK';
Expand All @@ -19,8 +20,10 @@ export type FdmPropertyType<NodeType> = Record<string, Record<string, NodeType>>

export type AddResourceOptions = AddReveal3DModelOptions | AddImageCollection360Options;

export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 };
export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes | '' };
export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 } & {
styling?: { default: NodeAppearance; mapped: NodeAppearance };
};
export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes };

export type NodeDataResult = {
nodeExternalId: string;
Expand Down
17 changes: 0 additions & 17 deletions react-components/src/hooks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,6 @@
* Copyright 2023 Cognite AS
*/
import { type CogniteExternalId, type CogniteInternalId } from '@cognite/sdk';
import { type Source } from '../utilities/FdmSDK';

export type FdmAssetMappingsConfig = {
/**
* 3D Data model source
*/
source: Source;
/*
* FDM space where model assets are located
*/
assetFdmSpace: string;
/*
* Global FDM 3D space
* TODO: Remove when the system data model is functional
*/
global3dSpace: string;
};

export type ThreeDModelMappings = {
modelId: number;
Expand Down
Loading
Loading