lost css
parent
c6a3803b8d
commit
b54b871fa3
|
@ -0,0 +1,185 @@
|
||||||
|
/* @tailwind base; */
|
||||||
|
|
||||||
|
.bg-gray-50 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgba(249, 250, 251, var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-col {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-start {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-6 {
|
||||||
|
height: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-lg {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml-2 {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-1 {
|
||||||
|
padding: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
--tw-shadow: 0 0 #0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
--tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
|
||||||
|
--tw-ring-offset-width: 0px;
|
||||||
|
--tw-ring-offset-color: #fff;
|
||||||
|
--tw-ring-color: rgba(59, 130, 246, 0.5);
|
||||||
|
--tw-ring-offset-shadow: 0 0 #0000;
|
||||||
|
--tw-ring-shadow: 0 0 #0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visible {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-6 {
|
||||||
|
width: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ping {
|
||||||
|
75%, 100% {
|
||||||
|
transform: scale(2);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
50% {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateY(-25%);
|
||||||
|
animation-timing-function: cubic-bezier(0.8,0,1,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: none;
|
||||||
|
animation-timing-function: cubic-bezier(0,0,0.2,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* html, */
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
font-family: sans-serif;
|
||||||
|
overflow: hidden;
|
||||||
|
--topNavH: 36px;
|
||||||
|
--sideNavW: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#c {
|
||||||
|
position: absolute;
|
||||||
|
width: calc(100% - var(--sideNavW));
|
||||||
|
height: calc(100% - var(--topNavH));
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topNav {
|
||||||
|
position: absolute;
|
||||||
|
height: var(--topNavH);
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
top:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sideNav {
|
||||||
|
position: absolute;
|
||||||
|
top: var(--topNavH);
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: var(--sideNavW);
|
||||||
|
}
|
||||||
|
|
||||||
|
#labels > div {
|
||||||
|
position: absolute;
|
||||||
|
border: solid 1px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
cursor: pointer;
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgba(243, 244, 246, var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgba(229, 231, 235, var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
fill: currentColor;
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgba(5, 150, 105, var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgba(4, 120, 87, var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1280px) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1536px) {
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<div id="react"></div>
|
<div id="react"></div>
|
||||||
<div id="labels"></div>
|
<div id="labels"></div>
|
||||||
<div id="stats"></div>
|
<div id="stats"></div>
|
||||||
<script src="index.bundle.js"></script>
|
<script src="app.bundle.js"></script>
|
||||||
<script src="scene.bundle.js"></script>
|
<script src="scene.bundle.js"></script>
|
||||||
<script src="solver.js"></script>
|
<script src="solver.js"></script>
|
||||||
<script src="lz-string.min.js"></script>
|
<script src="lz-string.min.js"></script>
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
|
|
||||||
import * as THREE from '../node_modules/three/src/Three';
|
import * as THREE from '../node_modules/three/src/Three';
|
||||||
|
|
||||||
import { drawOnClick1, drawOnClick2, drawPreClick2, drawClear } from './drawEvents'
|
|
||||||
import { onHover, onDrag, onDragDim, onPick, onRelease } from './mouseEvents'
|
|
||||||
import { addDimension, setCoincident } from './constraintEvents'
|
|
||||||
import { get3PtArc } from './drawArc'
|
|
||||||
import { _vec2, _vec3, raycaster, awaitPts } from './shared'
|
import { _vec2, _vec3, raycaster, awaitPts } from './shared'
|
||||||
|
|
||||||
|
import { drawOnClick1, drawOnClick2, drawPreClick2, drawClear } from './drawEvents'
|
||||||
|
import { onHover, onDrag, onPick, onRelease } from './mouseEvents'
|
||||||
|
import { setCoincident } from './constraintEvents'
|
||||||
|
import { get3PtArc } from './drawArc'
|
||||||
import { replacer, reviver } from './utils'
|
import { replacer, reviver } from './utils'
|
||||||
import { AxesHelper } from './sketchAxes'
|
import { AxesHelper } from './sketchAxes'
|
||||||
import { drawDimension, _onMoveDimension, setDimLines, updateDim } from './drawDimension';
|
import { drawDimension, _onMoveDimension, setDimLines, updateDim } from './drawDimension';
|
||||||
|
|
40
src/app.css
40
src/app.css
|
@ -1,38 +1,36 @@
|
||||||
/* @tailwind base; */
|
/* @tailwind base; */
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
html,
|
/* html, */
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
--topNavH: 36px;
|
||||||
|
--sideNavW: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#c {
|
#c {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: calc(100% - var(--sideNavW));
|
||||||
height: 100%;
|
height: calc(100% - var(--topNavH));
|
||||||
display: block;
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
}
|
}
|
||||||
|
.topNav {
|
||||||
#react > div {
|
position: absolute;
|
||||||
|
height: var(--topNavH);
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
top:0;
|
||||||
}
|
}
|
||||||
|
.sideNav {
|
||||||
.btn-red {
|
position: absolute;
|
||||||
cursor: pointer;
|
top: var(--topNavH);
|
||||||
@apply bg-red-500 hover:bg-red-600 text-gray-50;
|
left: 0;
|
||||||
}
|
bottom: 0;
|
||||||
|
width: var(--sideNavW);
|
||||||
.btn-grn {
|
|
||||||
cursor: pointer;
|
|
||||||
@apply bg-green-500 hover:bg-green-600 text-gray-50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-blu {
|
|
||||||
cursor: pointer;
|
|
||||||
@apply bg-blue-500 hover:bg-blue-600 text-gray-50;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
221
src/app.jsx
221
src/app.jsx
|
@ -1,214 +1,31 @@
|
||||||
|
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { createStore, applyMiddleware} from 'redux'
|
||||||
|
import { Provider } from 'react-redux'
|
||||||
|
import logger from 'redux-logger'
|
||||||
|
|
||||||
|
|
||||||
|
import { Tree } from './treeEntry'
|
||||||
|
import { NavBar } from './navBar'
|
||||||
|
import { reducer, preloadedState } from './reducer'
|
||||||
|
|
||||||
import React, { useEffect, useReducer, useRef, useState } from 'react';
|
|
||||||
import './app.css'
|
import './app.css'
|
||||||
|
|
||||||
import { Provider, useDispatch, useSelector } from 'react-redux'
|
|
||||||
|
|
||||||
import { FaCube, FaEdit } from 'react-icons/fa'
|
window.store = createStore(reducer, preloadedState, applyMiddleware(logger))
|
||||||
import { MdEdit, MdDone, MdVisibilityOff, MdVisibility, MdDelete } from 'react-icons/md'
|
|
||||||
import * as Icon from "./icons";
|
|
||||||
// import { color } from './shared'
|
|
||||||
|
|
||||||
export const Root = ({ store }) => (
|
|
||||||
|
const App = ({ store }) => (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App></App>
|
<NavBar />
|
||||||
|
<Tree />
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
ReactDOM.render(<App store={store} />, document.getElementById('react'));
|
||||||
const App = () => {
|
});
|
||||||
const dispatch = useDispatch()
|
|
||||||
const treeEntries = useSelector(state => state.treeEntries)
|
|
||||||
const activeSketchId = useSelector(state => state.activeSketchId)
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!activeSketchId) {
|
|
||||||
sc.canvas.addEventListener('pointermove', sc.onHover)
|
|
||||||
sc.canvas.addEventListener('pointerdown', sc.onPick)
|
|
||||||
return () => {
|
|
||||||
sc.canvas.removeEventListener('pointermove', sc.onHover)
|
|
||||||
sc.canvas.removeEventListener('pointerdown', sc.onPick)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [activeSketchId])
|
|
||||||
|
|
||||||
|
|
||||||
const btnz = [
|
|
||||||
activeSketchId ?
|
|
||||||
[MdDone, () => {
|
|
||||||
treeEntries.byId[activeSketchId].deactivate()
|
|
||||||
sc.activeSketch = null
|
|
||||||
// sc.activeDim = this.activeSketch.obj3d.children[1].children
|
|
||||||
}, 'Finish'] :
|
|
||||||
[FaEdit, sc.addSketch, 'Sketch']
|
|
||||||
,
|
|
||||||
[FaCube, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Extrude'],
|
|
||||||
[Icon.Union, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Union'],
|
|
||||||
[Icon.Subtract, () => {
|
|
||||||
if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return
|
|
||||||
// console.log('here')
|
|
||||||
const [m1, m2] = sc.selected
|
|
||||||
const mesh = subtract(m1, m2)
|
|
||||||
|
|
||||||
console.log(mesh, 'meshres')
|
|
||||||
dispatch({ type: 'rx-boolean', mesh, deps: [m1.name, m2.name] })
|
|
||||||
sc.render()
|
|
||||||
forceUpdate()
|
|
||||||
}, 'Subtract'],
|
|
||||||
[Icon.Intersect, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Intersect'],
|
|
||||||
[Icon.Dimension, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Dimension'],
|
|
||||||
[Icon.Line, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Line'],
|
|
||||||
[Icon.Arc, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc'],
|
|
||||||
]
|
|
||||||
|
|
||||||
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
|
||||||
|
|
||||||
return <>
|
|
||||||
<div className='absolute flex ml-auto mr-auto left-0 right-0 justify-center'>
|
|
||||||
{/* <div className='absolute flex justify-center'> */}
|
|
||||||
{
|
|
||||||
btnz.map(([Icon, fcn, txt], idx) => (
|
|
||||||
<div className="btn flex items-center justify-start p-1 text-lg" key={idx}
|
|
||||||
onClick={fcn}
|
|
||||||
>
|
|
||||||
<Icon className="w-6 h-6" />
|
|
||||||
<div className="ml-2">{txt}</div>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='absolute left-0 top-36 w-40 flex flex-col'>
|
|
||||||
{treeEntries.allIds.map((entId, idx) => (
|
|
||||||
<TreeEntry key={idx} entId={entId} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</>
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const TreeEntry = ({ entId }) => {
|
|
||||||
|
|
||||||
const treeEntries = useSelector(state => state.treeEntries.byId)
|
|
||||||
const dispatch = useDispatch()
|
|
||||||
|
|
||||||
const activeSketchId = useSelector(state => state.activeSketchId)
|
|
||||||
|
|
||||||
let obj3d, entry;
|
|
||||||
|
|
||||||
entry = treeEntries[entId]
|
|
||||||
|
|
||||||
if (entId[0] == "s") {
|
|
||||||
obj3d = treeEntries[entId].obj3d
|
|
||||||
} else {
|
|
||||||
obj3d = treeEntries[entId]
|
|
||||||
}
|
|
||||||
|
|
||||||
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
|
||||||
|
|
||||||
const vis = obj3d.visible
|
|
||||||
|
|
||||||
return <div className='bg-gray-50 flex justify-between w-full'>
|
|
||||||
<div className="btn"
|
|
||||||
onPointerEnter={() => {
|
|
||||||
if (entId[0] == 'm') {
|
|
||||||
// entry.material.color.set(color.hover)
|
|
||||||
sc.render()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onPointerLeave={() => {
|
|
||||||
const obj = entry
|
|
||||||
if (entId[0] == 'm' && !sc.selected.includes(obj)) {
|
|
||||||
// obj.material.color.set(color.mesh)
|
|
||||||
sc.render()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onPointerDown={() => {
|
|
||||||
if (entId[0] == 'm') {
|
|
||||||
sc.selected.push(
|
|
||||||
entry
|
|
||||||
)
|
|
||||||
sc.render()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{entId}
|
|
||||||
</div>
|
|
||||||
<div className='flex'>
|
|
||||||
<div className='btn'
|
|
||||||
onClick={() => {
|
|
||||||
activeSketchId && treeEntries[activeSketchId].deactivate()
|
|
||||||
entry.activate()
|
|
||||||
sc.clearSelection()
|
|
||||||
sc.activeSketch = entry;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MdEdit />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='btn'
|
|
||||||
onClick={() => {
|
|
||||||
dispatch({ type: 'delete-node', id: entId })
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MdDelete />
|
|
||||||
</div>
|
|
||||||
{
|
|
||||||
vis ?
|
|
||||||
<div className='btn'
|
|
||||||
onClick={() => {
|
|
||||||
obj3d.visible = false;
|
|
||||||
sc.render()
|
|
||||||
forceUpdate()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MdVisibility />
|
|
||||||
</div>
|
|
||||||
:
|
|
||||||
<div className='btn'
|
|
||||||
onClick={() => {
|
|
||||||
obj3d.visible = true;
|
|
||||||
sc.render()
|
|
||||||
forceUpdate()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MdVisibilityOff />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const subtract = (m1, m2) => {
|
|
||||||
// //Create a bsp tree from each of the meshes
|
|
||||||
// console.log(sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh'), "wtf")
|
|
||||||
|
|
||||||
|
|
||||||
let bspA = BoolOp.fromMesh(m1)
|
|
||||||
let bspB = BoolOp.fromMesh(m2)
|
|
||||||
m1.visible = false
|
|
||||||
m2.visible = false
|
|
||||||
|
|
||||||
// // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect
|
|
||||||
|
|
||||||
let bspResult = bspA.subtract(bspB)
|
|
||||||
|
|
||||||
// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh
|
|
||||||
|
|
||||||
let meshResult = BoolOp.toMesh(bspResult, m1.matrix, m1.material)
|
|
||||||
meshResult.userData.type = 'mesh'
|
|
||||||
meshResult.name = `${m1.name}-${m2.name}`
|
|
||||||
|
|
||||||
sc.obj3d.add(meshResult)
|
|
||||||
|
|
||||||
return meshResult
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ export function onHover(e) {
|
||||||
|
|
||||||
if (hoverPts.length) {
|
if (hoverPts.length) {
|
||||||
|
|
||||||
|
console.log(hoverPts)
|
||||||
// for (let i = 0; i < hoverPts.length; i++) {
|
// for (let i = 0; i < hoverPts.length; i++) {
|
||||||
// const obj = hoverPts[i].object
|
// const obj = hoverPts[i].object
|
||||||
// if (['point', 'plane'].includes(obj.userData.type)) {
|
// if (['point', 'plane'].includes(obj.userData.type)) {
|
||||||
|
@ -50,7 +51,6 @@ export function onHover(e) {
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// console.log(hoverPts)
|
|
||||||
|
|
||||||
|
|
||||||
let minDist = Infinity;
|
let minDist = Infinity;
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
|
||||||
|
|
||||||
|
import React, { useEffect, useReducer} from 'react';
|
||||||
|
|
||||||
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
|
||||||
|
import { FaCube, FaEdit } from 'react-icons/fa'
|
||||||
|
import { MdDone } from 'react-icons/md'
|
||||||
|
import * as Icon from "./icons";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const NavBar = () => {
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
const treeEntries = useSelector(state => state.treeEntries)
|
||||||
|
const activeSketchId = useSelector(state => state.activeSketchId)
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!activeSketchId) {
|
||||||
|
sc.canvas.addEventListener('pointermove', sc.onHover)
|
||||||
|
sc.canvas.addEventListener('pointerdown', sc.onPick)
|
||||||
|
return () => {
|
||||||
|
sc.canvas.removeEventListener('pointermove', sc.onHover)
|
||||||
|
sc.canvas.removeEventListener('pointerdown', sc.onPick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [activeSketchId])
|
||||||
|
|
||||||
|
|
||||||
|
const btnz = [
|
||||||
|
activeSketchId ?
|
||||||
|
[MdDone, () => {
|
||||||
|
treeEntries.byId[activeSketchId].deactivate()
|
||||||
|
sc.activeSketch = null
|
||||||
|
// sc.activeDim = this.activeSketch.obj3d.children[1].children
|
||||||
|
}, 'Finish'] :
|
||||||
|
[FaEdit, sc.addSketch, 'Sketch']
|
||||||
|
,
|
||||||
|
[FaCube, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Extrude'],
|
||||||
|
[Icon.Union, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Union'],
|
||||||
|
[Icon.Subtract, () => {
|
||||||
|
if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return
|
||||||
|
// console.log('here')
|
||||||
|
const [m1, m2] = sc.selected
|
||||||
|
const mesh = subtract(m1, m2)
|
||||||
|
|
||||||
|
console.log(mesh, 'meshres')
|
||||||
|
dispatch({ type: 'rx-boolean', mesh, deps: [m1.name, m2.name] })
|
||||||
|
sc.render()
|
||||||
|
forceUpdate()
|
||||||
|
}, 'Subtract'],
|
||||||
|
[Icon.Intersect, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Intersect'],
|
||||||
|
[Icon.Dimension, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Dimension'],
|
||||||
|
[Icon.Line, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Line'],
|
||||||
|
[Icon.Arc, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc'],
|
||||||
|
]
|
||||||
|
|
||||||
|
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
||||||
|
|
||||||
|
return <div className='topNav flex justify-center'>
|
||||||
|
{
|
||||||
|
btnz.map(([Icon, fcn, txt], idx) => (
|
||||||
|
<div className="btn flex items-center justify-start p-1 text-lg" key={idx}
|
||||||
|
onClick={fcn}
|
||||||
|
>
|
||||||
|
<Icon className="w-6 h-6" />
|
||||||
|
<div className="ml-2" tooltip="wtf">{txt}</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
const subtract = (m1, m2) => {
|
||||||
|
// //Create a bsp tree from each of the meshes
|
||||||
|
// console.log(sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh'), "wtf")
|
||||||
|
|
||||||
|
|
||||||
|
let bspA = BoolOp.fromMesh(m1)
|
||||||
|
let bspB = BoolOp.fromMesh(m2)
|
||||||
|
m1.visible = false
|
||||||
|
m2.visible = false
|
||||||
|
|
||||||
|
// // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect
|
||||||
|
|
||||||
|
let bspResult = bspA.subtract(bspB)
|
||||||
|
|
||||||
|
// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh
|
||||||
|
|
||||||
|
let meshResult = BoolOp.toMesh(bspResult, m1.matrix, m1.material)
|
||||||
|
meshResult.userData.type = 'mesh'
|
||||||
|
meshResult.name = `${m1.name}-${m2.name}`
|
||||||
|
|
||||||
|
sc.obj3d.add(meshResult)
|
||||||
|
|
||||||
|
return meshResult
|
||||||
|
|
||||||
|
}
|
|
@ -1,18 +1,19 @@
|
||||||
|
|
||||||
import ReactDOM from 'react-dom'
|
|
||||||
import React from 'react'
|
|
||||||
import { Root } from './app.jsx'
|
|
||||||
import update from 'immutability-helper';
|
|
||||||
|
|
||||||
import { createStore, applyMiddleware } from 'redux'
|
|
||||||
import logger from 'redux-logger'
|
|
||||||
|
|
||||||
import { DepTree } from './depTree.mjs'
|
import { DepTree } from './depTree.mjs'
|
||||||
|
import update from 'immutability-helper'
|
||||||
|
|
||||||
|
|
||||||
|
export const preloadedState = {
|
||||||
|
treeEntries: {
|
||||||
|
byId: {},
|
||||||
|
allIds: [],
|
||||||
|
tree: {},
|
||||||
|
order: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export function reducer(state = {}, action) {
|
||||||
function reducer(state = {}, action) {
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'rx-sketch':
|
case 'rx-sketch':
|
||||||
return update(state, {
|
return update(state, {
|
||||||
|
@ -84,21 +85,3 @@ function reducer(state = {}, action) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const preloadedState = {
|
|
||||||
treeEntries: {
|
|
||||||
byId: {},
|
|
||||||
allIds: [],
|
|
||||||
tree: {},
|
|
||||||
order: {},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
window.store = createStore(reducer, preloadedState, applyMiddleware(logger))
|
|
||||||
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
ReactDOM.render(<Root store={store} />, document.getElementById('react'));
|
|
||||||
});
|
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
|
||||||
|
|
||||||
|
import React, { useReducer } from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
import { MdEdit, MdVisibilityOff, MdVisibility, MdDelete } from 'react-icons/md'
|
||||||
|
|
||||||
|
|
||||||
|
export const Tree = () => {
|
||||||
|
const treeEntries = useSelector(state => state.treeEntries)
|
||||||
|
|
||||||
|
return <div className='sideNav flex flex-col'>
|
||||||
|
{treeEntries.allIds.map((entId, idx) => (
|
||||||
|
<TreeEntry key={idx} entId={entId} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const TreeEntry = ({ entId }) => {
|
||||||
|
|
||||||
|
const treeEntries = useSelector(state => state.treeEntries.byId)
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
|
const activeSketchId = useSelector(state => state.activeSketchId)
|
||||||
|
|
||||||
|
let obj3d, entry;
|
||||||
|
|
||||||
|
entry = treeEntries[entId]
|
||||||
|
|
||||||
|
if (entId[0] == "s") {
|
||||||
|
obj3d = treeEntries[entId].obj3d
|
||||||
|
} else {
|
||||||
|
obj3d = treeEntries[entId]
|
||||||
|
}
|
||||||
|
|
||||||
|
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
||||||
|
|
||||||
|
const vis = obj3d.visible
|
||||||
|
|
||||||
|
return <div className='bg-gray-50 flex justify-between w-full'>
|
||||||
|
<div className="btn"
|
||||||
|
onPointerEnter={() => {
|
||||||
|
if (entId[0] == 'm') {
|
||||||
|
// entry.material.color.set(color.hover)
|
||||||
|
sc.render()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onPointerLeave={() => {
|
||||||
|
const obj = entry
|
||||||
|
if (entId[0] == 'm' && !sc.selected.includes(obj)) {
|
||||||
|
// obj.material.color.set(color.mesh)
|
||||||
|
sc.render()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onPointerDown={() => {
|
||||||
|
if (entId[0] == 'm') {
|
||||||
|
sc.selected.push(
|
||||||
|
entry
|
||||||
|
)
|
||||||
|
sc.render()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{entId}
|
||||||
|
</div>
|
||||||
|
<div className='flex'>
|
||||||
|
<div className='btn'
|
||||||
|
onClick={() => {
|
||||||
|
activeSketchId && treeEntries[activeSketchId].deactivate()
|
||||||
|
entry.activate()
|
||||||
|
sc.clearSelection()
|
||||||
|
sc.activeSketch = entry;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdEdit />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='btn'
|
||||||
|
onClick={() => {
|
||||||
|
dispatch({ type: 'delete-node', id: entId })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdDelete />
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
vis ?
|
||||||
|
<div className='btn'
|
||||||
|
onClick={() => {
|
||||||
|
obj3d.visible = false;
|
||||||
|
sc.render()
|
||||||
|
forceUpdate()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdVisibility />
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className='btn'
|
||||||
|
onClick={() => {
|
||||||
|
obj3d.visible = true;
|
||||||
|
sc.render()
|
||||||
|
forceUpdate()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdVisibilityOff />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ const tailwindcss = require('tailwindcss')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
index: './src/index.jsx',
|
app: './src/app.jsx',
|
||||||
scene: './src/Scene.js',
|
scene: './src/Scene.js',
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
|
|
Loading…
Reference in New Issue