Skip to content

Commit

Permalink
Merge branch 'pramodcog/UX-1220' of https://github.com/cognitedata/re…
Browse files Browse the repository at this point in the history
…veal into pramodcog/UX-1220
  • Loading branch information
pramodcog committed Aug 21, 2023
2 parents 45dcfcc + dced329 commit fcb8b0e
Show file tree
Hide file tree
Showing 7 changed files with 329 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,17 @@
* Copyright 2023 Cognite AS
*/
import { type ReactElement, useEffect, useState } from 'react';
import {
type NodeAppearance,
type AddModelOptions,
type CogniteCadModel,
TreeIndexNodeCollection,
NodeIdNodeCollection,
DefaultNodeAppearance,
type NodeCollection,
type Cognite3DViewer
} from '@cognite/reveal';
import { type AddModelOptions, type CogniteCadModel } from '@cognite/reveal';
import { useReveal } from '../RevealContainer/RevealContext';
import { Matrix4 } from 'three';
import { useSDK } from '../RevealContainer/SDKProvider';
import { type CogniteClient } from '@cognite/sdk';
import { useRevealKeepAlive } from '../RevealKeepAlive/RevealKeepAliveContext';
import {
type CadModelStyling,
useApplyCadModelStyling,
modelExists
} from './useApplyCadModelStyling';

export type NodeStylingGroup = {
nodeIds: number[];
style?: NodeAppearance;
};

export type TreeIndexStylingGroup = {
treeIndices: number[];
style?: NodeAppearance;
};

export type CadModelStyling = {
defaultStyle?: NodeAppearance;
groups?: Array<NodeStylingGroup | TreeIndexStylingGroup>;
};

type CogniteCadModelProps = {
export type CogniteCadModelProps = {
addModelOptions: AddModelOptions;
styling?: CadModelStyling;
transform?: Matrix4;
Expand All @@ -47,13 +26,13 @@ export function CadModelContainer({
onLoad
}: 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 [model, setModel] = useState<CogniteCadModel | undefined>(
viewer.models.find(
(m) => m.modelId === addModelOptions.modelId && m.revisionId === addModelOptions.revisionId
) as CogniteCadModel | undefined
);

const { modelId, revisionId, geometryFilter } = addModelOptions;

Expand All @@ -63,33 +42,11 @@ export function CadModelContainer({

useEffect(() => {
if (!modelExists(model, viewer) || transform === undefined) return;

model.setModelTransformation(transform);
}, [transform, model]);

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

return () => {
if (!modelExists(model, viewer)) return;
void stylingCollections.then((nodeCollections) => {
nodeCollections.forEach((nodeCollection) => {
model.unassignStyledNodeCollection(nodeCollection);
});
});
};
}, [styleGroups, model]);

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

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

Expand Down Expand Up @@ -134,31 +91,3 @@ export function CadModelContainer({
setModel(undefined);
}
}

async function applyStyling(
sdk: CogniteClient,
model: CogniteCadModel,
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;
}

function modelExists(
model: CogniteCadModel | undefined,
viewer: Cognite3DViewer
): model is CogniteCadModel {
return model !== undefined && viewer.models.includes(model);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*!
* Copyright 2023 Cognite AS
*/
import {
type CogniteCadModel,
DefaultNodeAppearance,
type NodeAppearance,
type NodeCollection,
NodeIdNodeCollection,
TreeIndexNodeCollection,
type Cognite3DViewer
} from '@cognite/reveal';
import { useEffect } from 'react';
import { useSDK } from '../RevealContainer/SDKProvider';
import { type CogniteClient } from '@cognite/sdk';
import { isEqual } from 'lodash';
import { useReveal } from '../RevealContainer/RevealContext';

export type NodeStylingGroup = {
nodeIds: number[];
style?: NodeAppearance;
};

export type TreeIndexStylingGroup = {
treeIndices: number[];
style?: NodeAppearance;
};

export type CadModelStyling = {
defaultStyle?: NodeAppearance;
groups?: Array<NodeStylingGroup | TreeIndexStylingGroup>;
};

export const useApplyCadModelStyling = (
model?: CogniteCadModel,
modelStyling?: CadModelStyling
): void => {
const viewer = useReveal();
const sdk = useSDK();

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

useEffect(() => {
if (!modelExists(model, viewer) || styleGroups === undefined) return;

void applyStyling(sdk, model, styleGroups);
}, [styleGroups, model]);

useEffect(() => {
if (!modelExists(model, viewer)) return;

model.setDefaultNodeAppearance(defaultStyle);
}, [defaultStyle, model]);
};

async function applyStyling(
sdk: CogniteClient,
model: CogniteCadModel,
stylingGroups: Array<NodeStylingGroup | TreeIndexStylingGroup>
): Promise<void> {
const firstChangeIndex = getFirstChangeIndex();

for (let i = firstChangeIndex; i < model.styledNodeCollections.length; i++) {
const viewerStyledNodeCollection = model.styledNodeCollections[i];
model.unassignStyledNodeCollection(viewerStyledNodeCollection.nodeCollection);
}

for (let i = firstChangeIndex; i < stylingGroups.length; i++) {
const stylingGroup = stylingGroups[i];

if (stylingGroup.style === undefined) continue;

if ('treeIndices' in stylingGroup) {
const nodes = new TreeIndexNodeCollection(stylingGroup.treeIndices);
model.assignStyledNodeCollection(nodes, stylingGroup.style);
}

if ('nodeIds' in stylingGroup) {
const nodes = new NodeIdNodeCollection(sdk, model);
await nodes.executeFilter(stylingGroup.nodeIds);
model.assignStyledNodeCollection(nodes, stylingGroup.style);
}
}

function getFirstChangeIndex(): number {
for (let i = 0; i < model.styledNodeCollections.length; i++) {
const stylingGroup = stylingGroups[i];
const viewerStyledNodeCollection = model.styledNodeCollections[i];

const areEqual = isEqualStylingGroupAndCollection(stylingGroup, viewerStyledNodeCollection);

if (!areEqual) {
return i;
}
}

return model.styledNodeCollections.length;
}
}

function isEqualStylingGroupAndCollection(
group: NodeStylingGroup | TreeIndexStylingGroup,
collection: {
nodeCollection: NodeCollection;
appearance: NodeAppearance;
}
): boolean {
if (group?.style === undefined) return false;

const isEqualGroupStyle = isEqualStyle(collection.appearance, group.style);

if (collection.nodeCollection instanceof TreeIndexNodeCollection && 'treeIndices' in group) {
const compareCollection = new TreeIndexNodeCollection(group.treeIndices);
const isEqualContent = isEqualTreeIndex(collection.nodeCollection, compareCollection);

return isEqualGroupStyle && isEqualContent;
}

if (collection.nodeCollection instanceof NodeIdNodeCollection && 'nodeIds' in group) {
const collectionNodeIds = collection.nodeCollection.serialize().state.nodeIds as number[];
const isEqualContent = isEqual(collectionNodeIds, group.nodeIds);

return isEqualGroupStyle && isEqualContent;
}

return false;
}

function isEqualTreeIndex(
collectionA: TreeIndexNodeCollection,
collectionB: TreeIndexNodeCollection
): boolean {
const isEqualContent =
collectionA.getIndexSet().differenceWith(collectionB.getIndexSet()).count === 0;
return isEqualContent;
}

function isEqualStyle(styleA: NodeAppearance, styleB: NodeAppearance): boolean {
const { color: colorA, ...restA } = styleA;
const { color: colorB, ...restB } = styleB;

const color =
colorA === undefined || colorB === undefined
? Boolean(colorA ?? colorB)
: colorA.equals(colorB);

return color && isEqual(restA, restB);
}

export function modelExists(
model: CogniteCadModel | undefined,
viewer: Cognite3DViewer
): model is CogniteCadModel {
return model !== undefined && viewer.models.includes(model);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
*/
import { useRef, type ReactElement, useState, useEffect } from 'react';
import { type Cognite3DViewer } from '@cognite/reveal';
import { CadModelContainer, type CadModelStyling } from '../CadModelContainer/CadModelContainer';
import { CadModelContainer } from '../CadModelContainer/CadModelContainer';
import { type CadModelStyling } from '../CadModelContainer/useApplyCadModelStyling';
import {
PointCloudContainer,
type PointCloudModelStyling
Expand Down
8 changes: 4 additions & 4 deletions react-components/src/hooks/useCalculateModelsStyling.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ import {
type TypedReveal3DModel
} from '../components/Reveal3DResources/types';
import { type PointCloudModelStyling } from '../components/PointCloudContainer/PointCloudContainer';
import {
type NodeStylingGroup,
type CadModelStyling
} from '../components/CadModelContainer/CadModelContainer';
import { type InModel3dEdgeProperties } from '../utilities/globalDataModels';
import { type EdgeItem } from '../utilities/FdmSDK';
import { type NodeAppearance } from '@cognite/reveal';
Expand All @@ -18,6 +14,10 @@ import { type CogniteExternalId, type CogniteInternalId } from '@cognite/sdk';
import { useFdmAssetMappings } from './useFdmAssetMappings';
import { useEffect, useMemo } from 'react';
import { useMappedEdgesForRevisions } from '../components/NodeCacheProvider/NodeCacheProvider';
import {
type CadModelStyling,
type NodeStylingGroup
} from '../components/CadModelContainer/useApplyCadModelStyling';

type ModelStyleGroup = {
model: TypedReveal3DModel;
Expand Down
4 changes: 3 additions & 1 deletion react-components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export { use3DModelName } from './hooks/use3DModelName';
export { useFdmAssetMappings } from './hooks/useFdmAssetMappings';
export { useClickedNodeData, type ClickedNodeData } from './hooks/useClickedNode';
export { useCameraNavigation } from './hooks/useCameraNavigation';
export { useMappedEdgesForRevisions } from './components/NodeCacheProvider/NodeCacheProvider';

// Higher order components
export { withSuppressRevealEvents } from './higher-order-components/withSuppressRevealEvents';
Expand All @@ -30,11 +31,12 @@ export {
type PointCloudModelStyling,
type AnnotationIdStylingGroup
} from './components/PointCloudContainer/PointCloudContainer';
export { type CogniteCadModelProps } from './components/CadModelContainer/CadModelContainer';
export {
type CadModelStyling,
type TreeIndexStylingGroup,
type NodeStylingGroup
} from './components/CadModelContainer/CadModelContainer';
} from './components/CadModelContainer/useApplyCadModelStyling';
export {
type Reveal3DResourcesProps,
type FdmAssetStylingGroup,
Expand Down
Loading

0 comments on commit fcb8b0e

Please sign in to comment.