Skip to content

Commit

Permalink
push plane hash into url
Browse files Browse the repository at this point in the history
add extract hash direction from the url

add a check

move the ifcjs library version back to the latest

debugging plane hash

testing cut plane use effect

move plane creating logic into the use effect

debugging the model in the useEffect

debugging the model in the useEffect

subtract dependencies from the useEffect

add model check

add logs to the useEffect

subtract creating plane

use effect debug

working on the plane in the link direction

return the vector to enable cutplane

change the y normal direction

clean up

clean up cutPlane menu

deleted unused functions from the cutplane utility

address order of imports

clean up the cut plane utility

clean up

introduce toggle to the plane menu

clean up

calibrate normals agains the sp buildings
  • Loading branch information
OlegMoshkovich committed Aug 23, 2022
1 parent 7c636dc commit dfcca3e
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 158 deletions.
61 changes: 42 additions & 19 deletions src/Components/CutPlaneMenu.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React, {useState} from 'react'
import React, {useState, useEffect} from 'react'
import Menu from '@mui/material/Menu'
import MenuItem from '@mui/material/MenuItem'
import {makeStyles} from '@mui/styles'
import {TooltipIconButton} from './Buttons'
import {Vector3} from 'three'
import {useLocation} from 'react-router-dom'
import CutPlaneIcon from '../assets/2D_Icons/CutPlane.svg'
import useStore from '../store/useStore'
import {TooltipIconButton} from './Buttons'
import {getModelCenter} from '../utils/cutPlane'
import {Vector3} from 'three'
import {addHashParams, getHashParams, removeHashParams} from '../utils/location'


/**
* BasicMenu used when there are several option behind UI button
Expand All @@ -16,38 +19,62 @@ import {Vector3} from 'three'
*/
export default function CutPlaneMenu({listOfOptions, icon, title}) {
const [anchorEl, setAnchorEl] = useState(null)
const classes = useStyles()
const [cutPlaneDirection, setCutPlaneDirection] = useState('')
const open = Boolean(anchorEl)
const model = useStore((state) => state.modelStore)
const PLANE_PREFIX = 'p'
const classes = useStyles()

const handleClick = (event) => {
setAnchorEl(event.currentTarget)
}
const handleClose = () => {
setAnchorEl(null)
}
const viewer = useStore((state) => state.viewerStore)
const location = useLocation()

const createPlane = (normalDirection) => {
viewer.clipper.deleteAllPlanes()
const modelCenter = getModelCenter(model)
console.log('normal direction', normalDirection)
const planeHash = getHashParams(location, 'p')
if (normalDirection === cutPlaneDirection) {
viewer.clipper.deleteAllPlanes()
removeHashParams(window.location, PLANE_PREFIX)
setCutPlaneDirection('')
return
}
let normal
switch (normalDirection) {
case 'x':
normal = new Vector3(1, 0, 0)
normal = new Vector3(-1, 0, 0)
break
case 'y':
normal = new Vector3(0, 1, 0)
normal = new Vector3(0, -1, 0)
break
case 'z':
normal = new Vector3(0, 0, 1)
normal = new Vector3(0, 0, -1)
break
default:
normal = new Vector3(0, 1, 0)
break
}
if (!planeHash || planeHash !== normalDirection ) {
addHashParams(window.location, PLANE_PREFIX, {planeAxis: normalDirection})
}
setCutPlaneDirection(normalDirection)
return viewer.clipper.createFromNormalAndCoplanarPoint(normal, modelCenter)
}

useEffect(() => {
const planeHash = getHashParams(location, 'p')
if (planeHash && model && viewer) {
const planeDirection = planeHash.split(':')[1]
createPlane(planeDirection)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [model])

return (
<div>
<TooltipIconButton
Expand All @@ -61,19 +88,19 @@ export default function CutPlaneMenu({listOfOptions, icon, title}) {
anchorEl={anchorEl}
open={open}
onClose={handleClose}
className={classes.root}
anchorOrigin={{vertical: 'top', horizontal: 'center'}}
transformOrigin={{vertical: 'top', horizontal: 'center'}}
className={classes.root}
PaperProps={{
style: {
left: '300px',
transform: 'translateX(-40px) translateY(-40px)',
},
}}
>
<MenuItem onClick={() => createPlane('x')}> X</MenuItem>
<MenuItem onClick={() => createPlane('y')}>Y</MenuItem>
<MenuItem onClick={() => createPlane('z')}>Z</MenuItem>
<MenuItem onClick={() => createPlane('x')} selected={cutPlaneDirection === 'x'}> X</MenuItem>
<MenuItem onClick={() => createPlane('y')} selected={cutPlaneDirection === 'y'}>Y</MenuItem>
<MenuItem onClick={() => createPlane('z')} selected={cutPlaneDirection === 'z'}>Z</MenuItem>
</Menu>
</div>
)
Expand All @@ -82,12 +109,8 @@ export default function CutPlaneMenu({listOfOptions, icon, title}) {

const useStyles = makeStyles({
root: {
'& .MuiMenu-root': {
position: 'absolute',
left: '-200px',
top: '200px',
'& .Mui-selected': {
border: '1px solid lightGray',
},
},
},
)

})
4 changes: 2 additions & 2 deletions src/Components/OperationsGroup.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React from 'react'
import {makeStyles} from '@mui/styles'
import useStore from '../store/useStore'
import CameraControl from './CameraControl'
import CutPlaneMenu from './CutPlaneMenu'
import ShareControl from './ShareControl'
import ShortcutsControl from './ShortcutsControl'
import {TooltipIconButton} from './Buttons'
import ClearIcon from '../assets/2D_Icons/Clear.svg'
import MarkupIcon from '../assets/2D_Icons/Markup.svg'
import ListIcon from '../assets/2D_Icons/List.svg'
import useStore from '../store/useStore'
import CutPlaneMenu from './CutPlaneMenu'


/**
Expand Down
149 changes: 12 additions & 137 deletions src/utils/cutPlane.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,45 +27,42 @@ export function getSelectionAxisFromBoundingBox(boundingBox) {


/**
* getModelCenter is the helper method for the cutplane logic
*
* @param {Object} ifcModel bouding box
* @return {Object} centerCoordinates
*/
/**
* getModelCenter is the helper method for the cutplane logic
* getModelCenter return the center of the model based on bounding box
*
* @param {Object} ifcModel bouding box
* @return {Object} centerCoordinates
*/
export function getModelCenter(ifcModel) {
return {
x:
return new Vector3(
(ifcModel?.geometry.boundingBox.max.x +
ifcModel?.geometry.boundingBox.min.x) /
2,
y:
(ifcModel?.geometry.boundingBox.max.y +
ifcModel?.geometry.boundingBox.min.y) /
2,
z:
(ifcModel?.geometry.boundingBox.max.z +
ifcModel?.geometry.boundingBox.min.z) /
2,
}
)
}


/**
* getElementBoundingBox is the helper method to get a bounding box of the element
* getElementBoundingBox creates a bounding box around the model
*
* @param {Object} selection bouding box
* @return {Object} centerCoordinates
* @param {Object} selection seclected meshes
* @return {Object} boudingBox geometry
*/
export function getElementBoundingBox(selection) {
const geometry = new BufferGeometry()
const coordinates = []
const alreadySaved = new Set()
const position = selection.geometry.attributes['position']
const vertices = Float32Array.from(coordinates)
const mesh = new Mesh(geometry)
const boundingBox = new Box3()
geometry.setAttribute('position', new BufferAttribute(vertices, selection.geometry.index.count))
boundingBox.setFromObject(mesh)

for (let i = 0; i < selection.geometry.index.array.length; i++) {
if (!alreadySaved.has(selection.geometry.index.array[i])) {
Expand All @@ -76,128 +73,6 @@ export function getElementBoundingBox(selection) {
}
}

const vertices = Float32Array.from(coordinates)
geometry.setAttribute('position', new BufferAttribute(vertices, selection.geometry.index.count))
const mesh = new Mesh(geometry)
const boundingBox = new Box3()
boundingBox.setFromObject(mesh)
return boundingBox
}

/**
* toggleClippingPlane turns clipping plane on and off
*
* @param {Boolean } on bouding box
* @param {Number} expressId centerCoordinates
* @param {IfcViewerAPI } ifcViewer bouding box
*/
export function toggleClippingPlane(on, expressId, ifcViewer) {
if (on) {
const modelCenter = getModelCenter()
const boundingBox = getElementBoundingBox(ifcViewer?.IFC.selector.selection.mesh)
const selectionAxis = getSelectionAxisFromBoundingBox(boundingBox)

let direction = 1

let normal
if (
selectionAxis.x.size < selectionAxis.y.size &&
selectionAxis.x.size < selectionAxis.z.size
) {
if (selectionAxis.x.center > modelCenter.x) {
direction = -1
}
normal = new Vector3(direction, 0, 0)
} else if (
selectionAxis.y.size < selectionAxis.x.size &&
selectionAxis.y.size < selectionAxis.z.size
) {
if (selectionAxis.y.center > modelCenter.y) {
direction = -1
}
normal = new Vector3(0, direction, 0)
} else {
if (selectionAxis.z.center > modelCenter.z) {
direction = -1
}
normal = new Vector3(0, 0, direction)
}

const point = new Vector3(
selectionAxis.x.center,
selectionAxis.y.center,
selectionAxis.z.center,
)

ifcViewer?.clipper.createFromNormalAndCoplanarPoint(normal, point)
ifcViewer?.IFC.selector.unpickIfcItems()
} else {
removePlanes(ifcViewer)
showElement([expressId], true)
}
}


/**
* toggleClippingPlane turns clipping plane on and off
*
* @param {IfcViewerAPI } viewer bouding box
*/
function removePlanes(viewer) {

This comment has been minimized.

Copy link
@mkeshavarzi

mkeshavarzi Aug 26, 2022

Contributor

Hey Oleg - Maybe I'm missing something but I can't seem to understand why we are removing these functions. I'm using the removePlanes function for the extract level feature.

viewer?.clipper.deleteAllPlanes()
const clippingPlanes = viewer?.clipper['context'].clippingPlanes
for (const plane of clippingPlanes) {
viewer?.clipper['context'].removeClippingPlane(plane)
}
}


/**
* toggleClippingPlane turns clipping plane on and off
*
* @param {Number} expressId centerCoordinates
* @param {Boolean } select bouding box
* @param {IfcViewerAPI } ifcViewer bouding box
*/
export function showElement(expressId, select, ifcViewer) {
const subset = getSubset(expressId)
ifcViewer?.context.scene.scene.add(subset)
if (select) {
expressId.forEach((element) => selectElement(element))
}
}


/**
* selectElement turns clipping plane on and off
*
* @param {Number} expressId centerCoordinates
* @param {IfcViewerAPI } ifcViewer bouding box
* @param {IfcModel } ifcModel bouding box
*/
async function selectElement(expressId, ifcViewer, ifcModel) {
ifcViewer?.IFC.selector.selection.pickByID(
ifcModel.modelID,
[expressId],
true,
)
}


/**
* selectElement turns clipping plane on and off
*
* @param {Number[]} expressId centerCoordinates
* @param {IfcViewerAPI } ifcViewer bouding box
* @param {IfcModel } ifcModel bouding box
* @return {Object}
*/
export function getSubset(expressId, ifcViewer, ifcModel) {
return ifcViewer?.IFC.loader.ifcManager.createSubset({
modelID: ifcModel.modelID,
removePrevious: true,
ids: expressId,
scene: ifcViewer?.context.scene.scene,
})
}

0 comments on commit dfcca3e

Please sign in to comment.