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(fe2): Update Section Box controls to include visibility #3333

Merged
merged 23 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a4ce150
Update Section Box controls to include visibility
andrewwallacespeckle Oct 17, 2024
4707635
Update reset v-if
andrewwallacespeckle Oct 17, 2024
5bd230a
Update shortcut
andrewwallacespeckle Oct 17, 2024
5e9c116
Merge branch 'main' into andrew/web-1962-hide-section-box
andrewwallacespeckle Oct 17, 2024
48ce936
Added render requests so that section box updates are made visible
AlexandruPopovici Oct 17, 2024
d665408
Merge branch 'main' into andrew/web-1962-hide-section-box
andrewwallacespeckle Oct 18, 2024
830ba34
Remove comments
andrewwallacespeckle Oct 18, 2024
04c18e8
Exposed SectionToolEvent in the viewer
AlexandruPopovici Oct 18, 2024
802e362
Only show reset when change has been made to sectionbox
andrewwallacespeckle Oct 18, 2024
7d123d7
Merge branch 'main' into andrew/web-1962-hide-section-box
andrewwallacespeckle Oct 18, 2024
3b9847c
gql
andrewwallacespeckle Oct 18, 2024
013502f
Merge branch 'main' into andrew/web-1962-hide-section-box
andrewwallacespeckle Oct 21, 2024
3080ba6
Merge branch 'main' into andrew/web-1962-hide-section-box
andrewwallacespeckle Oct 21, 2024
1697b12
Make state reactive
andrewwallacespeckle Oct 21, 2024
410aa1b
Merge branch 'main' into andrew/web-1962-hide-section-box
andrewwallacespeckle Oct 21, 2024
1ecb03c
Revert "Make state reactive"
andrewwallacespeckle Oct 21, 2024
5f45335
Handles WEB-2039
AlexandruPopovici Oct 21, 2024
f779ebb
Handles WEB-2035
AlexandruPopovici Oct 22, 2024
6d42537
Merge branch 'andrew/web-1962-hide-section-box' of https://github.com…
andrewwallacespeckle Oct 22, 2024
c4fcaef
Merge branch 'main' into andrew/web-1962-hide-section-box
andrewwallacespeckle Oct 23, 2024
87a2400
Merge branch 'main' into andrew/web-1962-hide-section-box
andrewwallacespeckle Oct 23, 2024
d77792e
Merge branch 'main' into andrew/web-1962-hide-section-box
andrewwallacespeckle Oct 24, 2024
56ea9ec
Changes from call with Fabs
andrewwallacespeckle Oct 24, 2024
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
46 changes: 31 additions & 15 deletions packages/frontend-2/components/viewer/Controls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
v-tippy="isSmallerOrEqualSm ? undefined : sectionBoxShortcut"
flat
secondary
:active="isSectionBoxEnabled"
:active="isSectionBoxVisible"
@click="toggleSectionBox()"
>
<ScissorsIcon class="h-4 w-4 md:h-5 md:w-5" />
Expand Down Expand Up @@ -238,6 +238,9 @@
</div>
</div>
</div>
<Portal v-if="isSectionBoxEnabled && isSectionBoxEdited" to="pocket-actions">
<FormButton @click="resetSectionBox()">Reset section box</FormButton>
</Portal>
</div>
<div v-else />
</template>
Expand Down Expand Up @@ -268,7 +271,6 @@ import {
useInjectedViewerState
} from '~~/lib/viewer/composables/setup'
import { useMixpanel } from '~~/lib/core/composables/mp'

import { useIsSmallerOrEqualThanBreakpoint } from '~~/composables/browser'
import { useEmbed } from '~/lib/viewer/composables/setup/embed'
import { useViewerTour } from '~/lib/viewer/composables/tour'
Expand Down Expand Up @@ -346,7 +348,13 @@ type ActiveControl =
| 'gendo'

const { resourceItems, modelsAndVersionIds } = useInjectedViewerLoadedResources()
const { toggleSectionBox, isSectionBoxEnabled } = useSectionBoxUtilities()
const {
resetSectionBox,
isSectionBoxEnabled,
isSectionBoxVisible,
toggleSectionBox,
isSectionBoxEdited
} = useSectionBoxUtilities()
const { getActiveMeasurement, removeMeasurement, enableMeasurements } =
useMeasurementUtilities()
const { showNavbar, showControls } = useViewerTour()
Expand Down Expand Up @@ -491,14 +499,6 @@ const trackAndtoggleProjection = () => {
})
}

watch(isSectionBoxEnabled, (val) => {
mp.track('Viewer Action', {
type: 'action',
name: 'section-box',
status: val
})
})

const scrollControlsToBottom = () => {
// TODO: Currently this will scroll to the very bottom, which doesn't make sense when there are multiple models loaded
// if (scrollableControlsContainer.value)
Expand All @@ -515,10 +515,6 @@ onMounted(() => {
activeControl.value = isSmallerOrEqualSm.value ? 'none' : 'models'
})

watch(isSmallerOrEqualSm, (newVal) => {
activeControl.value = newVal ? 'none' : 'models'
})

onKeyStroke('Escape', () => {
const isActiveMeasurement = getActiveMeasurement()

Expand All @@ -531,4 +527,24 @@ onKeyStroke('Escape', () => {
activeControl.value = 'none'
}
})

watch(isSmallerOrEqualSm, (newVal) => {
activeControl.value = newVal ? 'none' : 'models'
})

watch(isSectionBoxEnabled, (val) => {
mp.track('Viewer Action', {
type: 'action',
name: 'section-box',
status: val
})
})

watch(isSectionBoxVisible, (val) => {
mp.track('Viewer Action', {
type: 'action',
name: 'section-box-visibility',
status: val
})
})
</script>
8 changes: 8 additions & 0 deletions packages/frontend-2/lib/viewer/composables/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ export type InjectableViewerState = Readonly<{
enabled: Ref<boolean>
}
sectionBox: Ref<Nullable<Box3>>
sectionBoxContext: {
visible: Ref<boolean>
edited: Ref<boolean>
}
highlightedObjectIds: Ref<string[]>
lightConfig: Ref<SunLightConfiguration>
explodeFactor: Ref<number>
Expand Down Expand Up @@ -988,6 +992,10 @@ function setupInterfaceState(
isOrthoProjection
},
sectionBox: ref(null as Nullable<Box3>),
sectionBoxContext: {
visible: ref(false),
edited: ref(false)
},
filters: {
isolatedObjectIds,
hiddenObjectIds,
Expand Down
52 changes: 48 additions & 4 deletions packages/frontend-2/lib/viewer/composables/setup/postSetup.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { difference, flatten, isEqual, uniq } from 'lodash-es'
import { ViewerEvent, VisualDiffMode, CameraController } from '@speckle/viewer'
import {
ViewerEvent,
VisualDiffMode,
CameraController,
UpdateFlags,
SectionOutlines,
SectionToolEvent,
SectionTool
} from '@speckle/viewer'
import type {
PropertyInfo,
StringPropertyInfo,
Expand Down Expand Up @@ -293,10 +301,20 @@ function useViewerSubscriptionEventTracker() {

function useViewerSectionBoxIntegration() {
const {
ui: { sectionBox },
ui: {
sectionBox,
sectionBoxContext: { visible, edited }
},
viewer: { instance }
} = useInjectedViewerState()

// Change edited=true when user starts changing the section box by dragging it
const sectionTool = instance.getExtension(SectionTool)
const onDragStart = () => {
edited.value = true
}
sectionTool.on(SectionToolEvent.DragStart, onDragStart)

// No two-way sync for section boxes, because once you set a Box3 into the viewer
// the viewer transforms it into something else causing the updates going into an infinite loop

Expand All @@ -308,24 +326,50 @@ function useViewerSectionBoxIntegration() {
if (!newVal && !oldVal) return

if (oldVal && !newVal) {
visible.value = false
edited.value = false

instance.sectionBoxOff()
instance.requestRender()
instance.requestRender(UpdateFlags.RENDER_RESET)
return
}

if (newVal && (!oldVal || !newVal.equals(oldVal))) {
visible.value = true
edited.value = false

instance.setSectionBox({
min: newVal.min,
max: newVal.max
})
instance.sectionBoxOn()
instance.requestRender()
const outlines = instance.getExtension(SectionOutlines)
if (outlines) outlines.requestUpdate()
instance.requestRender(UpdateFlags.RENDER_RESET)
}
},
{ immediate: true, deep: true, flush: 'sync' }
)

watch(
visible,
(newVal, oldVal) => {
if (newVal && oldVal) return
if (!newVal && !oldVal) return

if (newVal) {
sectionTool.visible = true
} else {
sectionTool.visible = false
}
instance.requestRender()
},
{ immediate: true, deep: true, flush: 'sync' }
)

onBeforeUnmount(() => {
instance.sectionBoxOff()
sectionTool.removeListener(SectionToolEvent.DragStart, onDragStart)
})
}

Expand Down
52 changes: 41 additions & 11 deletions packages/frontend-2/lib/viewer/composables/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,69 @@ import {
} from '~~/lib/viewer/composables/setup'
import { useDiffBuilderUtilities } from '~~/lib/viewer/composables/setup/diff'
import { useTourStageState } from '~~/lib/viewer/composables/tour'
import { Vector3, Box3 } from 'three'

export function useSectionBoxUtilities() {
const { instance } = useInjectedViewer()
const {
sectionBox,
filters: { selectedObjects }
sectionBoxContext: { visible, edited },
filters: { selectedObjects },
threads: {
openThread: { thread }
}
} = useInjectedViewerInterfaceState()

const isSectionBoxEnabled = computed(() => !!sectionBox.value)
const toggleSectionBox = () => {
if (isSectionBoxEnabled.value) {
sectionBox.value = null
return
}
const isSectionBoxVisible = computed(() => visible.value)
const isSectionBoxEdited = computed(() => edited.value)

const resolveSectionBoxFromSelection = () => {
const objectIds = selectedObjects.value.map((o) => o.id).filter(isNonNullable)
const box = instance.getSectionBoxFromObjects(objectIds)
sectionBox.value = box
}
const sectionBoxOn = () => {

const toggleSectionBox = () => {
if (!isSectionBoxEnabled.value) {
toggleSectionBox()
resolveSectionBoxFromSelection()
return
}

if (isSectionBoxVisible.value) {
visible.value = false
} else {
visible.value = true
}
}
const sectionBoxOff = () => {

const resetSectionBox = () => {
const serializedSectionBox = thread.value?.viewerState?.ui.sectionBox
sectionBox.value = null

if (serializedSectionBox) {
// Same logic we have in deserialization
sectionBox.value = new Box3(
new Vector3(
serializedSectionBox.min[0],
serializedSectionBox.min[1],
serializedSectionBox.min[2]
),
new Vector3(
serializedSectionBox.max[0],
serializedSectionBox.max[1],
serializedSectionBox.max[2]
)
)
}
}

return {
isSectionBoxEnabled,
isSectionBoxVisible,
isSectionBoxEdited,
toggleSectionBox,
sectionBoxOn,
sectionBoxOff,
resetSectionBox,
sectionBox
}
}
Expand Down
4 changes: 3 additions & 1 deletion packages/viewer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { type CanonicalView } from './modules/extensions/CameraController.js'
import { CameraEvent, CameraEventPayload } from './modules/objects/SpeckleCamera.js'
import {
SectionTool,
SectionToolEvent,
SectionToolEventPayload
} from './modules/extensions/SectionTool.js'
import { SectionOutlines } from './modules/extensions/SectionOutlines.js'
Expand Down Expand Up @@ -132,7 +133,8 @@ export {
SpeckleGeometryConverter,
Assets,
AssetType,
HybridCameraController
HybridCameraController,
SectionToolEvent
}

export type {
Expand Down
8 changes: 8 additions & 0 deletions packages/viewer/src/modules/World.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,12 @@ export class World {
const dist = offsetBox.max.distanceTo(sizeBox.max)
return dist
}

public getRelativeOffsetBox(box: Box3, offsetAmount: number = 0.001) {
this.MatBuff.identity()
this.MatBuff.makeScale(1 + offsetAmount, 1 + offsetAmount, 1 + offsetAmount)
const offsetBox = new Box3().copy(box)
offsetBox.applyMatrix4(this.MatBuff)
return offsetBox
}
}
5 changes: 5 additions & 0 deletions packages/viewer/src/modules/extensions/SectionOutlines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ export class SectionOutlines extends Extension {
}
}

public requestUpdate() {
this.setSectionPlaneChanged(this.viewer.getRenderer().clippingPlanes)
this.updateOutlines(this.sectionPlanesChanged)
}

private updatePlaneOutline(
batches: MeshBatch[],
_plane: Plane,
Expand Down
24 changes: 16 additions & 8 deletions packages/viewer/src/modules/extensions/SectionTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,17 +467,25 @@ export class SectionTool extends Extension {
box = new Box3(new Vector3(-1, -1, -1), new Vector3(1, 1, 1))
}

let x1, y1, z1, x2, y2, z2

if (offset === 0) {
offset = this.viewer.World.getRelativeOffset()
const offsetBox = this.viewer.World.getRelativeOffsetBox(box, 0.0001)
x1 = offsetBox.min.x //box.min.x - (box.max.x - box.min.x) * offset
y1 = offsetBox.min.y //box.min.y - (box.max.y - box.min.y) * offset
z1 = offsetBox.min.z //box.min.z - (box.max.z - box.min.z) * offset
x2 = offsetBox.max.x //box.max.x + (box.max.x - box.min.x) * offset
y2 = offsetBox.max.y //box.max.y + (box.max.y - box.min.y) * offset
z2 = offsetBox.max.z //box.max.z + (box.max.z - box.min.z) * offset
} else {
x1 = box.min.x - (box.max.x - box.min.x) * offset
y1 = box.min.y - (box.max.y - box.min.y) * offset
z1 = box.min.z - (box.max.z - box.min.z) * offset
x2 = box.max.x + (box.max.x - box.min.x) * offset
y2 = box.max.y + (box.max.y - box.min.y) * offset
z2 = box.max.z + (box.max.z - box.min.z) * offset
}

const x1 = box.min.x - (box.max.x - box.min.x) * offset
const y1 = box.min.y - (box.max.y - box.min.y) * offset
const z1 = box.min.z - (box.max.z - box.min.z) * offset
const x2 = box.max.x + (box.max.x - box.min.x) * offset
const y2 = box.max.y + (box.max.y - box.min.y) * offset
const z2 = box.max.z + (box.max.z - box.min.z) * offset

const newVertices = [
x1,
y1,
Expand Down
Loading