12545c6f16
* feat(viewer-lib): WIP on the new OrientedSectionTool * feat(viewer-lib): Added proper face pulling for the oriented section box * feat(viewer-lib): Several updates on the oriented sectioning tool - Implemented section planes calculation and propagation - Unified obb computation from all gizmos - Implemented proper setBox function - Updated the viewer-core to work with OBB instead of AABB for it's clipping volume - Updated the intersections to work with OBB for their intersting bounds - Added extension methods to Box3 and OBB * feat(viewer-lib): Better way of handling gizmo input events overlapping * fix(viewer-lib): Updated clippingVolume occurences to OBB * feat(viewer-lib): Section outlines now work with oriented section tool! * feat(viewer-lib): Integrated new section tool with the frontend and API - Defined an archtype for SectionTool which all section tools can derive from - The old section tool is renamed to AxisAlignedSectionTool - Replaced the old section tool with the oriented one in the frontend * fix(viewer-lib): Fixed compile errors * feat(viewer-lib): Some updates: - Section tool outline, the visible box, is now rendered as before however it's correctly being RTE'd. And we can also make it thinner/thicker now - Fixed the issue where the scale controls had 'exponential' growth. It's now linear like the translate one * feat(viewer-lib): Implemented highlghting the box face when clicking on it to extend/retract it * fix(viewer-lib): A bunch of fixes for the oriented section tool * feat(viewer-lib): Some updates: - Documented new OrientedSectionTool code - Fixed som issues related to section box reseting - Hid the translation and rotation gizmos that we aren't using - Tidied up a bit * feat(viewer-lib): Set the translate and rotate gizmos in local space so the rotation will affect them as wll * chore(viewer-lib): Purged the old section tool * chore(viewer-lib): Updated section box data type. Updated LegacyViewer section box data handling. Updated frontend to use new data type. Still not working doe * fix(viewer-lib): Fixed an issue where comments with section boxes did not enable section outlines at startup * chore(frontend): Fixed ci compiler error * fix(viewer-lib): Fixes WEB-1593
200 lines
5.8 KiB
TypeScript
200 lines
5.8 KiB
TypeScript
import {
|
|
ConvertLegacyDataToState,
|
|
GetViewerResourcesForComments
|
|
} from '@/modules/comments/domain/operations'
|
|
import { LegacyCommentViewerData } from '@/modules/core/graph/generated/graphql'
|
|
import { viewerResourcesToString } from '@/modules/core/services/commit/viewerResources'
|
|
import { Nullable, SpeckleViewer } from '@speckle/shared'
|
|
import { has, get, intersection, isObjectLike } from 'lodash'
|
|
|
|
type SerializedViewerState = SpeckleViewer.ViewerState.SerializedViewerState
|
|
|
|
export type LegacyData = Partial<LegacyCommentViewerData>
|
|
|
|
export type DataStruct = {
|
|
version: number
|
|
state: SerializedViewerState
|
|
}
|
|
|
|
export function inputToDataStruct(
|
|
inputSerializedViewerState: unknown
|
|
): Nullable<DataStruct> {
|
|
const state = SpeckleViewer.ViewerState.isSerializedViewerState(
|
|
inputSerializedViewerState
|
|
)
|
|
? inputSerializedViewerState
|
|
: null
|
|
if (!state) return null
|
|
|
|
return {
|
|
version: SpeckleViewer.ViewerState.SERIALIZED_VIEWER_STATE_VERSION,
|
|
state
|
|
}
|
|
}
|
|
|
|
export function isDataStruct(data: unknown): data is DataStruct {
|
|
if (!data) return false
|
|
if (!has(data, 'version')) return false
|
|
const stateRaw = get(data, 'state')
|
|
return SpeckleViewer.ViewerState.isSerializedViewerState(stateRaw)
|
|
}
|
|
|
|
export const formatSerializedViewerState =
|
|
SpeckleViewer.ViewerState.formatSerializedViewerState
|
|
|
|
export function isLegacyData(data: unknown): data is LegacyData {
|
|
if (!data) return false
|
|
const keys: Array<keyof LegacyData> = [
|
|
'camPos',
|
|
'filters',
|
|
'location',
|
|
'sectionBox',
|
|
'selection'
|
|
]
|
|
if (!isObjectLike(data)) return false
|
|
|
|
const valKeys = Object.keys(data as Record<string, unknown>)
|
|
if (intersection(valKeys, keys).length !== keys.length) return false
|
|
|
|
return true
|
|
}
|
|
|
|
export function convertStateToLegacyData(state: SerializedViewerState): LegacyData {
|
|
const camPos = state.ui.camera.position
|
|
const camTarget = state.ui.camera.target
|
|
const zoom = state.ui.camera.zoom
|
|
const isOrtho = state.ui.camera.isOrthoProjection
|
|
const selection = state.ui.selection
|
|
const selectionLocation = selection || camTarget
|
|
|
|
const ret: LegacyData = {
|
|
camPos: [
|
|
camPos[0] || 0,
|
|
camPos[1] || 0,
|
|
camPos[2] || 0,
|
|
camTarget[0] || 0,
|
|
camTarget[1] || 0,
|
|
camTarget[2] || 0,
|
|
zoom || 1,
|
|
isOrtho ? 1 : 0
|
|
],
|
|
filters: {
|
|
passMin: state.viewer.metadata.filteringState?.passMin || null,
|
|
passMax: state.viewer.metadata.filteringState?.passMax || null,
|
|
hiddenIds: state.ui.filters.hiddenObjectIds.slice(),
|
|
isolatedIds: state.ui.filters.isolatedObjectIds.slice(),
|
|
sectionBox: {
|
|
min: (state.ui?.sectionBox?.min as number[]) || [0, 0, 0],
|
|
max: (state.ui?.sectionBox?.max as number[]) || [0, 0, 0],
|
|
rotation: (state.ui?.sectionBox?.rotation as number[]) || [
|
|
1, 0, 0, 0, 1, 0, 0, 0, 1
|
|
]
|
|
},
|
|
propertyInfoKey: state.ui.filters.propertyFilter.key
|
|
},
|
|
location: {
|
|
x: selectionLocation[0] || 0,
|
|
y: selectionLocation[1] || 0,
|
|
z: selectionLocation[2] || 0
|
|
},
|
|
sectionBox: {
|
|
min: (state.ui?.sectionBox?.min as number[]) || [0, 0, 0],
|
|
max: (state.ui?.sectionBox?.max as number[]) || [0, 0, 0],
|
|
rotation: (state.ui?.sectionBox?.rotation as number[]) || [
|
|
1, 0, 0, 0, 1, 0, 0, 0, 1
|
|
]
|
|
},
|
|
selection: null
|
|
}
|
|
return ret
|
|
}
|
|
|
|
export const convertLegacyDataToStateFactory =
|
|
(deps: {
|
|
getViewerResourcesForComments: GetViewerResourcesForComments
|
|
}): ConvertLegacyDataToState =>
|
|
async (data, comment) => {
|
|
const resources = await deps.getViewerResourcesForComments(comment.streamId, [
|
|
comment.id
|
|
])
|
|
const sectionBox = data.filters?.sectionBox || data.sectionBox
|
|
|
|
const ret: SerializedViewerState = {
|
|
projectId: comment.streamId,
|
|
sessionId: 'legacy-sessionId',
|
|
viewer: {
|
|
metadata: {
|
|
filteringState: {
|
|
passMax: data.filters?.passMax,
|
|
passMin: data.filters?.passMin
|
|
}
|
|
}
|
|
},
|
|
resources: {
|
|
request: {
|
|
resourceIdString: viewerResourcesToString(resources),
|
|
threadFilters: {
|
|
includeArchived: false,
|
|
loadedVersionsOnly: false
|
|
}
|
|
}
|
|
},
|
|
ui: {
|
|
threads: {
|
|
openThread: {
|
|
threadId: null,
|
|
isTyping: false,
|
|
newThreadEditor: true
|
|
}
|
|
},
|
|
spotlightUserSessionId: null,
|
|
explodeFactor: 0,
|
|
filters: {
|
|
isolatedObjectIds: data.filters?.isolatedIds || [],
|
|
hiddenObjectIds: data.filters?.hiddenIds || [],
|
|
selectedObjectIds: [],
|
|
propertyFilter: {
|
|
key: data.filters?.propertyInfoKey || null,
|
|
isApplied: true
|
|
}
|
|
},
|
|
camera: {
|
|
position: [
|
|
data.camPos?.[0] || 0,
|
|
data.camPos?.[1] || 0,
|
|
data.camPos?.[2] || 0
|
|
],
|
|
target: [data.camPos?.[3] || 0, data.camPos?.[4] || 0, data.camPos?.[5] || 0],
|
|
isOrthoProjection: !!data.camPos?.[6],
|
|
zoom: data.camPos?.[7] || 1
|
|
},
|
|
viewMode: 0,
|
|
sectionBox: sectionBox
|
|
? {
|
|
min: (sectionBox.min as number[]) || [0, 0, 0],
|
|
max: (sectionBox.max as number[]) || [0, 0, 0],
|
|
rotation: (sectionBox.rotation as number[]) || [1, 0, 0, 0, 1, 0, 0, 0, 1]
|
|
}
|
|
: null,
|
|
lightConfig: {},
|
|
selection: data.location
|
|
? [
|
|
data.location.x as number,
|
|
data.location.y as number,
|
|
data.location.z as number
|
|
]
|
|
: null,
|
|
diff: {
|
|
command: null,
|
|
mode: 1,
|
|
time: 0.5
|
|
},
|
|
measurement: {
|
|
enabled: false,
|
|
options: null
|
|
}
|
|
}
|
|
}
|
|
return ret
|
|
}
|