-
-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5e35a19
commit 0faf530
Showing
6 changed files
with
204 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import React, {useState, useEffect} from 'react' | ||
import Menu from '@mui/material/Menu' | ||
import MenuItem from '@mui/material/MenuItem' | ||
import {makeStyles} from '@mui/styles' | ||
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 {addHashParams, getHashParams, removeHashParams} from '../utils/location' | ||
|
||
|
||
/** | ||
* BasicMenu used when there are several option behind UI button | ||
* show/hide from the right of the screen. | ||
* @param {Array} listOfOptions Title for the drawer | ||
* @return {Object} ItemPropertiesDrawer react component | ||
*/ | ||
export default function CutPlaneMenu({listOfOptions, icon, title}) { | ||
const [anchorEl, setAnchorEl] = useState(null) | ||
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) | ||
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) | ||
break | ||
case 'y': | ||
normal = new Vector3(0, -1, 0) | ||
break | ||
case 'z': | ||
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 | ||
title={'Cut Planes'} | ||
icon={<CutPlaneIcon/>} | ||
onClick={handleClick} | ||
/> | ||
<Menu | ||
elevation={1} | ||
id='basic-menu' | ||
anchorEl={anchorEl} | ||
open={open} | ||
onClose={handleClose} | ||
className={classes.root} | ||
anchorOrigin={{vertical: 'top', horizontal: 'center'}} | ||
transformOrigin={{vertical: 'top', horizontal: 'center'}} | ||
PaperProps={{ | ||
style: { | ||
left: '300px', | ||
transform: 'translateX(-40px) translateY(-40px)', | ||
}, | ||
}} | ||
> | ||
<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> | ||
) | ||
} | ||
|
||
|
||
const useStyles = makeStyles({ | ||
root: { | ||
'& .Mui-selected': { | ||
border: '1px solid lightGray', | ||
}, | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import {Box3, BufferAttribute, BufferGeometry, Mesh, Vector3} from 'three' | ||
|
||
|
||
/* eslint-disable no-magic-numbers */ | ||
/** | ||
* getSelectionAxisFromBoundingBox is the helper method for the cutplane logic | ||
* | ||
* @param {Object} boundingBox bouding box | ||
* @return {Object} | ||
*/ | ||
export function getSelectionAxisFromBoundingBox(boundingBox) { | ||
return { | ||
x: { | ||
size: Math.abs( boundingBox.max.x - boundingBox.min.x), | ||
center: (boundingBox.max.x + boundingBox.min.x) / 2, | ||
}, | ||
y: { | ||
size: Math.abs( boundingBox.max.y - boundingBox.min.y), | ||
center: (boundingBox.max.y + boundingBox.min.y) / 2, | ||
}, | ||
z: { | ||
size: Math.abs(boundingBox.max.z - boundingBox.min.z ), | ||
center: (boundingBox.max.z + boundingBox.min.z) / 2, | ||
}, | ||
} | ||
} | ||
|
||
|
||
/** | ||
* getModelCenter return the center of the model based on bounding box | ||
* | ||
* @param {Object} ifcModel bouding box | ||
* @return {Object} centerCoordinates | ||
*/ | ||
export function getModelCenter(ifcModel) { | ||
return new Vector3( | ||
(ifcModel?.geometry.boundingBox.max.x + | ||
ifcModel?.geometry.boundingBox.min.x) / | ||
2, | ||
(ifcModel?.geometry.boundingBox.max.y + | ||
ifcModel?.geometry.boundingBox.min.y) / | ||
2, | ||
(ifcModel?.geometry.boundingBox.max.z + | ||
ifcModel?.geometry.boundingBox.min.z) / | ||
2, | ||
) | ||
} | ||
|
||
|
||
/** | ||
* getElementBoundingBox creates a bounding box around the model | ||
* | ||
* @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])) { | ||
coordinates.push(position.getX(selection.geometry.index.array[i])) | ||
coordinates.push(position.getY(selection.geometry.index.array[i])) | ||
coordinates.push(position.getZ(selection.geometry.index.array[i])) | ||
alreadySaved.add(selection.geometry.index.array[i]) | ||
} | ||
} | ||
|
||
return boundingBox | ||
} | ||
|