Skip to content

Commit

Permalink
fix: changing default style does not update styling (#3613)
Browse files Browse the repository at this point in the history
* fix: changing default style does not update styling

* fix: memoize filtered cad options

---------

Co-authored-by: cognite-bulldozer[bot] <51074376+cognite-bulldozer[bot]@users.noreply.github.com>
  • Loading branch information
christjt and cognite-bulldozer[bot] authored Aug 25, 2023
1 parent d20c6da commit e97539c
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const FdmNodeCacheContext = createContext<FdmNodeCacheContent | undefined

export const useMappedEdgesForRevisions = (
modelRevisionIds: Array<{ modelId: number; revisionId: number }>,
enabled: boolean
enabled = true
): UseQueryResult<ModelRevisionToEdgeMap> => {
const content = useContext(FdmNodeCacheContext);

Expand Down Expand Up @@ -81,7 +81,9 @@ export const useFdmAssetMappings = (
return useQuery(
['reveal', 'react-components', 'fdm-asset-mappings', fdmAssetExternalIds],
async () => {
return await nodeCacheContent?.cache.getMappingsForFdmIds(fdmAssetExternalIds, models);
return (
(await nodeCacheContent?.cache.getMappingsForFdmIds(fdmAssetExternalIds, models)) ?? []
);
},
{
enabled: fdmAssetExternalIds.length > 0 && models.length > 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*!
* Copyright 2023 Cognite AS
*/
import { useRef, type ReactElement, useState, useEffect } from 'react';
import { useRef, type ReactElement, useState, useEffect, useMemo } from 'react';
import { type Cognite3DViewer } from '@cognite/reveal';
import { CadModelContainer } from '../CadModelContainer/CadModelContainer';
import { type CadModelStyling } from '../CadModelContainer/useApplyCadModelStyling';
Expand All @@ -17,9 +17,10 @@ import {
type TypedReveal3DModel,
type AddResourceOptions,
type Reveal3DResourcesProps,
type DefaultResourceStyling
type CadModelOptions,
type PointCloudModelOptions
} from './types';
import { useCalculateModelsStyling } from '../../hooks/useCalculateModelsStyling';
import { useCalculateCadStyling } from '../../hooks/useCalculateModelsStyling';

export const Reveal3DResources = ({
resources,
Expand All @@ -33,18 +34,27 @@ export const Reveal3DResources = ({
const numModelsLoaded = useRef(0);

useEffect(() => {
getTypedModels(resources, viewer)
.then((models) => {
models.forEach((model) => {
setDefaultResourceStyling(model, defaultResourceStyling);
});
return models;
})
.then(setReveal3DModels)
.catch(console.error);
getTypedModels(resources, viewer).then(setReveal3DModels).catch(console.error);
}, [resources, viewer]);

const reveal3DModelsStyling = useCalculateModelsStyling(reveal3DModels, instanceStyling ?? []);
const cadModelOptions = useMemo(
() => reveal3DModels.filter((model): model is CadModelOptions => model.type === 'cad'),
[reveal3DModels]
);

const pointCloudModelOptions = useMemo(
() =>
reveal3DModels.filter(
(model): model is PointCloudModelOptions => model.type === 'pointcloud'
),
[reveal3DModels]
);

const styledCadModelOptions = useCalculateCadStyling(
cadModelOptions,
instanceStyling ?? [],
defaultResourceStyling
);

const image360CollectionAddOptions = resources.filter(
(resource): resource is AddImageCollection360Options =>
Expand All @@ -61,40 +71,38 @@ export const Reveal3DResources = ({

return (
<>
{reveal3DModels
.map((modelData, index) => ({
...modelData,
styling: reveal3DModelsStyling[index] as CadModelStyling
}))
.filter(({ type }) => type === 'cad')
.map((modelData, index) => {
return (
<CadModelContainer
key={`${modelData.modelId}/${modelData.revisionId}/${index}`}
addModelOptions={modelData}
styling={modelData.styling}
transform={modelData.transform}
onLoad={onModelLoaded}
/>
);
})}
{reveal3DModels
.map((modelData, index) => ({
...modelData,
styling: reveal3DModelsStyling[index] as PointCloudModelStyling
}))
.filter(({ type }) => type === 'pointcloud')
.map((modelData, index) => {
return (
<PointCloudContainer
key={`${modelData.modelId}/${modelData.revisionId}/${index}`}
addModelOptions={modelData}
styling={modelData.styling}
transform={modelData.transform}
onLoad={onModelLoaded}
/>
);
})}
{styledCadModelOptions.map(({ styleGroups, model }, index) => {
const defaultStyle = model.styling?.default ?? defaultResourceStyling?.cad?.default;
const cadStyling: CadModelStyling = {
defaultStyle,
groups: styleGroups
};
return (
<CadModelContainer
key={`${model.modelId}/${model.revisionId}/${index}`}
addModelOptions={model}
styling={cadStyling}
transform={model.transform}
onLoad={onModelLoaded}
/>
);
})}
{pointCloudModelOptions.map((pointCloudModelOptions, index) => {
const { modelId, revisionId, transform, styling } = pointCloudModelOptions;
const defaultStyle = styling?.default ?? defaultResourceStyling?.pointcloud?.default;
const pcStyling: PointCloudModelStyling = {
defaultStyle
};
return (
<PointCloudContainer
key={`${modelId}/${revisionId}/${index}`}
addModelOptions={pointCloudModelOptions}
styling={pcStyling}
transform={transform}
onLoad={onModelLoaded}
/>
);
})}
{image360CollectionAddOptions.map((addModelOption) => {
return (
<Image360CollectionContainer
Expand Down Expand Up @@ -134,18 +142,3 @@ async function getTypedModels(
})
);
}

function setDefaultResourceStyling(
model: TypedReveal3DModel,
defaultResourceStyling?: DefaultResourceStyling
): void {
if (model.styling !== undefined || defaultResourceStyling === undefined) {
return;
}

if (model.type === 'cad') {
model.styling = defaultResourceStyling.cad;
} else if (model.type === 'pointcloud') {
model.styling = defaultResourceStyling.pointcloud;
}
}
18 changes: 12 additions & 6 deletions react-components/src/components/Reveal3DResources/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
* Copyright 2023 Cognite AS
*/

import {
type NodeAppearance,
type AddModelOptions,
type SupportedModelTypes
} from '@cognite/reveal';
import { type NodeAppearance, type AddModelOptions } from '@cognite/reveal';

import { type Matrix4 } from 'three';
import { type DmsUniqueIdentifier, type Source } from '../../utilities/FdmSDK';
Expand All @@ -23,7 +19,17 @@ export type AddResourceOptions = AddReveal3DModelOptions | AddImageCollection360
export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 } & {
styling?: { default?: NodeAppearance; mapped?: NodeAppearance };
};
export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes };
export type TypedReveal3DModel = CadModelOptions | PointCloudModelOptions;

export type CadModelOptions = { type: 'cad' } & AddModelOptions & { transform?: Matrix4 } & {
styling?: { default?: NodeAppearance; mapped?: NodeAppearance };
};

export type PointCloudModelOptions = { type: 'pointcloud' } & AddModelOptions & {
transform?: Matrix4;
} & {
styling?: { default?: NodeAppearance };
};

export type NodeDataResult = {
fdmNode: DmsUniqueIdentifier;
Expand Down
87 changes: 52 additions & 35 deletions react-components/src/hooks/useCalculateModelsStyling.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* Copyright 2023 Cognite AS
*/
import {
type FdmAssetStylingGroup,
type TypedReveal3DModel
type CadModelOptions,
type DefaultResourceStyling,
type FdmAssetStylingGroup
} from '../components/Reveal3DResources/types';
import { type PointCloudModelStyling } from '../components/PointCloudContainer/PointCloudContainer';
import { type NodeAppearance } from '@cognite/reveal';
import { type ThreeDModelMappings } from './types';
import { type Node3D, type CogniteExternalId } from '@cognite/sdk';
Expand All @@ -15,18 +15,32 @@ import {
} from '../components/NodeCacheProvider/NodeCacheProvider';
import { useMemo } from 'react';
import { type FdmEdgeWithNode, type TreeIndex } from '../components/NodeCacheProvider/types';
import { type CadModelStyling, type NodeStylingGroup, type TreeIndexStylingGroup } from '..';
import {
type NodeStylingGroup,
type TreeIndexStylingGroup
} from '../components/CadModelContainer/useApplyCadModelStyling';

type ModelStyleGroup = {
model: TypedReveal3DModel;
model: CadModelOptions;
styleGroup: Array<NodeStylingGroup | TreeIndexStylingGroup>;
};

export const useCalculateModelsStyling = (
models: TypedReveal3DModel[],
instanceGroups: FdmAssetStylingGroup[]
): Array<PointCloudModelStyling | CadModelStyling> => {
const modelsMappedStyleGroups = useCalculateMappedStyling(models);
export type CadStyleGroup = NodeStylingGroup | TreeIndexStylingGroup;

export type StyledModel = {
model: CadModelOptions;
styleGroups: CadStyleGroup[];
};

export const useCalculateCadStyling = (
models: CadModelOptions[],
instanceGroups: FdmAssetStylingGroup[],
defaultResourceStyling?: DefaultResourceStyling
): StyledModel[] => {
const modelsMappedStyleGroups = useCalculateMappedStyling(
models,
defaultResourceStyling?.cad?.mapped
);
const modelInstanceStyleGroups = useCalculateInstanceStyling(models, instanceGroups);
console.log('Model instance style groups = ', modelInstanceStyleGroups);
const joinedStyleGroups = useJoinStylingGroups(
Expand All @@ -37,14 +51,13 @@ export const useCalculateModelsStyling = (
return joinedStyleGroups;
};

function useCalculateMappedStyling(models: TypedReveal3DModel[]): ModelStyleGroup[] {
const modelsRevisionsWithMappedEquipment = models.filter(
(model) => model.styling?.mapped !== undefined
);
const shouldFetchAllMappedEquipment = modelsRevisionsWithMappedEquipment.length > 0;
function useCalculateMappedStyling(
models: CadModelOptions[],
defaultMappedNodeAppearance?: NodeAppearance
): ModelStyleGroup[] {
const modelsRevisionsWithMappedEquipment = useMemo(() => getMappedCadModelsOptions(), [models]);
const { data: mappedEquipmentEdges } = useMappedEdgesForRevisions(
modelsRevisionsWithMappedEquipment,
shouldFetchAllMappedEquipment
modelsRevisionsWithMappedEquipment
);

const modelsMappedStyleGroups = useMemo(() => {
Expand All @@ -55,23 +68,28 @@ function useCalculateMappedStyling(models: TypedReveal3DModel[]): ModelStyleGrou
) {
return [];
}

return models.map((model) => {
return modelsRevisionsWithMappedEquipment.map((model) => {
const fdmData = mappedEquipmentEdges?.get(`${model.modelId}/${model.revisionId}`) ?? [];
const modelStyle = model.styling?.mapped ?? defaultMappedNodeAppearance;

const styleGroup =
model.styling?.mapped !== undefined
? [getMappedStyleGroup(fdmData, model.styling.mapped)]
: [];
const styleGroup = modelStyle !== undefined ? [getMappedStyleGroup(fdmData, modelStyle)] : [];
return { model, styleGroup };
});
}, [models, mappedEquipmentEdges]);
}, [modelsRevisionsWithMappedEquipment, mappedEquipmentEdges, defaultMappedNodeAppearance]);

return modelsMappedStyleGroups;

function getMappedCadModelsOptions(): CadModelOptions[] {
if (defaultMappedNodeAppearance !== undefined) {
return models;
}

return models.filter((model) => model.styling?.mapped !== undefined);
}
}

function useCalculateInstanceStyling(
models: TypedReveal3DModel[],
models: CadModelOptions[],
instanceGroups: FdmAssetStylingGroup[]
): ModelStyleGroup[] {
const { data: fdmAssetMappings } = useFdmAssetMappings(
Expand All @@ -96,10 +114,10 @@ function useCalculateInstanceStyling(
}

function useJoinStylingGroups(
models: TypedReveal3DModel[],
models: CadModelOptions[],
modelsMappedStyleGroups: ModelStyleGroup[],
modelInstanceStyleGroups: ModelStyleGroup[]
): Array<PointCloudModelStyling | CadModelStyling> {
): StyledModel[] {
const modelsStyling = useMemo(() => {
if (modelInstanceStyleGroups.length === 0 && modelsMappedStyleGroups.length === 0) {
return extractDefaultStyles(models);
Expand All @@ -111,21 +129,20 @@ function useJoinStylingGroups(
.filter((typedModel) => typedModel.model === model)
.flatMap((typedModel) => typedModel.styleGroup);
return {
defaultStyle: model.styling?.default,
groups: [...mappedStyleGroup, ...instanceStyleGroups]
model,
styleGroups: [...mappedStyleGroup, ...instanceStyleGroups]
};
});
}, [models, modelInstanceStyleGroups, modelsMappedStyleGroups]);

return modelsStyling;
}

function extractDefaultStyles(
typedModels: TypedReveal3DModel[]
): Array<PointCloudModelStyling | CadModelStyling> {
function extractDefaultStyles(typedModels: CadModelOptions[]): StyledModel[] {
return typedModels.map((model) => {
return {
defaultStyle: model.styling?.default
model,
styleGroups: []
};
});
}
Expand All @@ -144,7 +161,7 @@ function getMappedStyleGroup(
function calculateCadModelStyling(
stylingGroups: FdmAssetStylingGroup[],
mappings: ThreeDModelMappings[],
model: TypedReveal3DModel
model: CadModelOptions
): TreeIndexStylingGroup[] {
const modelMappings = getModelMappings(mappings, model);

Expand All @@ -169,7 +186,7 @@ function getNodeSubtreeIndices(node: Node3D): TreeIndex[] {

function getModelMappings(
mappings: ThreeDModelMappings[],
model: TypedReveal3DModel
model: CadModelOptions
): Map<CogniteExternalId, Node3D> {
return mappings
.filter(
Expand Down
2 changes: 1 addition & 1 deletion react-components/stories/CadStylingCache.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const Models = ({ addModelOptions }: CogniteCadModelProps): JSX.Element => {

const [platformStyling, setPlatformStyling] = useState<CadModelStyling>();

const { data } = useMappedEdgesForRevisions([platformModelOptions], true);
const { data } = useMappedEdgesForRevisions([platformModelOptions]);

const nodeIds = useMemo(
() =>
Expand Down

0 comments on commit e97539c

Please sign in to comment.