working dependency tree
parent
40a692ed6a
commit
3b49000e2b
|
@ -10,6 +10,7 @@
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"css-loader": "^5.1.3",
|
"css-loader": "^5.1.3",
|
||||||
"gh-pages": "^3.1.0",
|
"gh-pages": "^3.1.0",
|
||||||
|
"immutability-helper": "^3.1.1",
|
||||||
"mini-css-extract-plugin": "^1.4.0",
|
"mini-css-extract-plugin": "^1.4.0",
|
||||||
"postcss": "^8.2.9",
|
"postcss": "^8.2.9",
|
||||||
"postcss-loader": "^5.2.0",
|
"postcss-loader": "^5.2.0",
|
||||||
|
@ -3633,6 +3634,12 @@
|
||||||
"postcss": "^8.1.0"
|
"postcss": "^8.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/immutability-helper": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/immutability-helper/-/immutability-helper-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/import-fresh": {
|
"node_modules/import-fresh": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||||
|
@ -11406,6 +11413,12 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"immutability-helper": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/immutability-helper/-/immutability-helper-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"import-fresh": {
|
"import-fresh": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"css-loader": "^5.1.3",
|
"css-loader": "^5.1.3",
|
||||||
"gh-pages": "^3.1.0",
|
"gh-pages": "^3.1.0",
|
||||||
|
"immutability-helper": "^3.1.1",
|
||||||
"mini-css-extract-plugin": "^1.4.0",
|
"mini-css-extract-plugin": "^1.4.0",
|
||||||
"postcss": "^8.2.9",
|
"postcss": "^8.2.9",
|
||||||
"postcss-loader": "^5.2.0",
|
"postcss-loader": "^5.2.0",
|
||||||
|
|
70
src/app.jsx
70
src/app.jsx
|
@ -5,8 +5,7 @@ import './app.css'
|
||||||
|
|
||||||
import { Provider, useDispatch, useSelector } from 'react-redux'
|
import { Provider, useDispatch, useSelector } from 'react-redux'
|
||||||
import { FaCube, FaEdit } from 'react-icons/fa'
|
import { FaCube, FaEdit } from 'react-icons/fa'
|
||||||
import { MdEdit, MdDone, MdVisibilityOff, MdVisibility } from 'react-icons/md'
|
import { MdEdit, MdDone, MdVisibilityOff, MdVisibility, MdDelete } from 'react-icons/md'
|
||||||
import { RiShape2Fill } from 'react-icons/ri'
|
|
||||||
import * as Icon from "./icons";
|
import * as Icon from "./icons";
|
||||||
import { color } from './utils/shared'
|
import { color } from './utils/shared'
|
||||||
|
|
||||||
|
@ -22,16 +21,11 @@ export const Root = ({ store }) => (
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const treeEntries = useSelector(state => state.treeEntries)
|
const treeEntries = useSelector(state => state.treeEntries)
|
||||||
const activeSketchNid = useSelector(state => state.activeSketchNid)
|
const activeSketchId = useSelector(state => state.activeSketchId)
|
||||||
|
|
||||||
// const [state, setState] = useState('x')
|
|
||||||
// useEffect(()=>{
|
|
||||||
// console.log('hereeee')
|
|
||||||
// },[state])
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeSketchNid) {
|
if (!activeSketchId) {
|
||||||
sc.canvas.addEventListener('pointermove', sc.onHover)
|
sc.canvas.addEventListener('pointermove', sc.onHover)
|
||||||
sc.canvas.addEventListener('pointerdown', sc.onPick)
|
sc.canvas.addEventListener('pointerdown', sc.onPick)
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -39,27 +33,38 @@ const App = () => {
|
||||||
sc.canvas.removeEventListener('pointerdown', sc.onPick)
|
sc.canvas.removeEventListener('pointerdown', sc.onPick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [activeSketchNid])
|
}, [activeSketchId])
|
||||||
|
|
||||||
|
|
||||||
const btnz = [
|
const btnz = [
|
||||||
activeSketchNid ?
|
activeSketchId ?
|
||||||
[MdDone, () => {
|
[MdDone, () => {
|
||||||
treeEntries.byNid[activeSketchNid].deactivate()
|
treeEntries.byId[activeSketchId].deactivate()
|
||||||
sc.activeSketch = null
|
sc.activeSketch = null
|
||||||
// sc.activeDim = this.activeSketch.obj3d.children[1].children
|
// sc.activeDim = this.activeSketch.obj3d.children[1].children
|
||||||
}, 'Finish'] :
|
}, 'Finish'] :
|
||||||
[FaEdit, sc.addSketch, 'Sketch']
|
[FaEdit, sc.addSketch, 'Sketch']
|
||||||
,
|
,
|
||||||
[FaCube, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Extrude'],
|
[FaCube, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Extrude'],
|
||||||
[Icon.Union, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Union'],
|
[Icon.Union, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Union'],
|
||||||
[Icon.Subtract, subtract, 'Subtract'],
|
[Icon.Subtract, ()=> {
|
||||||
[Icon.Intersect, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Intersect'],
|
if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return
|
||||||
[Icon.Dimension, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Dimension'],
|
// console.log('here')
|
||||||
[Icon.Line, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Line'],
|
const [m1, m2] = sc.selected
|
||||||
[Icon.Arc, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Arc'],
|
const mesh = subtract(m1,m2)
|
||||||
|
|
||||||
|
dispatch({ type: 'rx-extrusion', 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 left-0 w-40 flex flex-col'>
|
return <div className='absolute left-0 w-40 flex flex-col'>
|
||||||
{
|
{
|
||||||
btnz.map(([Icon, fcn, txt], idx) => (
|
btnz.map(([Icon, fcn, txt], idx) => (
|
||||||
|
@ -73,7 +78,7 @@ const App = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
<div className=''>
|
<div className=''>
|
||||||
{treeEntries.allNids.map((entId, idx) => (
|
{treeEntries.allIds.map((entId, idx) => (
|
||||||
<TreeEntry key={idx} entId={entId} />
|
<TreeEntry key={idx} entId={entId} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -84,9 +89,10 @@ const App = () => {
|
||||||
|
|
||||||
const TreeEntry = ({ entId }) => {
|
const TreeEntry = ({ entId }) => {
|
||||||
|
|
||||||
const treeEntries = useSelector(state => state.treeEntries.byNid)
|
const treeEntries = useSelector(state => state.treeEntries.byId)
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
const activeSketchNid = useSelector(state => state.activeSketchNid)
|
const activeSketchId = useSelector(state => state.activeSketchId)
|
||||||
|
|
||||||
let obj3d, entry;
|
let obj3d, entry;
|
||||||
|
|
||||||
|
@ -105,7 +111,7 @@ const TreeEntry = ({ entId }) => {
|
||||||
return <div className='bg-gray-50 flex justify-between w-full'>
|
return <div className='bg-gray-50 flex justify-between w-full'>
|
||||||
<div className='btn'
|
<div className='btn'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
activeSketchNid && treeEntries[activeSketchNid].deactivate()
|
activeSketchId && treeEntries[activeSketchId].deactivate()
|
||||||
entry.activate()
|
entry.activate()
|
||||||
sc.activeSketch = entry;
|
sc.activeSketch = entry;
|
||||||
}}
|
}}
|
||||||
|
@ -113,6 +119,13 @@ const TreeEntry = ({ entId }) => {
|
||||||
<MdEdit />
|
<MdEdit />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className='btn'
|
||||||
|
onClick={() => {
|
||||||
|
dispatch({type:'delete-node',id:entId})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdDelete/>
|
||||||
|
</div>
|
||||||
{
|
{
|
||||||
vis ?
|
vis ?
|
||||||
<div className='btn'
|
<div className='btn'
|
||||||
|
@ -165,12 +178,10 @@ const TreeEntry = ({ entId }) => {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const subtract = () => {
|
const subtract = (m1,m2) => {
|
||||||
// //Create a bsp tree from each of the meshes
|
// //Create a bsp tree from each of the meshes
|
||||||
// console.log(sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh'), "wtf")
|
// console.log(sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh'), "wtf")
|
||||||
if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return
|
|
||||||
// console.log('here')
|
|
||||||
const [m1, m2] = sc.selected
|
|
||||||
|
|
||||||
let bspA = BoolOp.fromMesh(m1)
|
let bspA = BoolOp.fromMesh(m1)
|
||||||
let bspB = BoolOp.fromMesh(m2)
|
let bspB = BoolOp.fromMesh(m2)
|
||||||
|
@ -184,9 +195,12 @@ const subtract = () => {
|
||||||
// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh
|
// //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)
|
let meshResult = BoolOp.toMesh(bspResult, m1.matrix, m1.material)
|
||||||
|
meshResult.userData.type = 'mesh'
|
||||||
|
meshResult.userData.name = `${m1.name}-${m2.name}`
|
||||||
|
|
||||||
sc.obj3d.add(meshResult)
|
sc.obj3d.add(meshResult)
|
||||||
sc.render()
|
|
||||||
|
return meshResult
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
class DepTree {
|
||||||
|
constructor() {
|
||||||
|
this.tree = {}
|
||||||
|
this.order = {}
|
||||||
|
this.arr = []
|
||||||
|
}
|
||||||
|
|
||||||
|
addParent(id) {
|
||||||
|
if (this.tree[id]) return
|
||||||
|
this.tree[id] = new Set()
|
||||||
|
this.order[id] = this.arr.length
|
||||||
|
this.arr.push(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild(childId, ...parentIds) {
|
||||||
|
for (let parentId of parentIds) {
|
||||||
|
this.tree[parentId].add(childId)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addParent(childId)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
deleteNode(id) {
|
||||||
|
this.visited = new Set()
|
||||||
|
|
||||||
|
this.nodesToDel = []
|
||||||
|
this.dfs(id)
|
||||||
|
|
||||||
|
const idx = []
|
||||||
|
this.nodesToDel.sort((a, b) => this.order[b] - this.order[a])
|
||||||
|
|
||||||
|
for (let id of this.nodesToDel) {
|
||||||
|
idx.push(this.order[id])
|
||||||
|
this.arr.splice(this.order[id], 1)
|
||||||
|
delete this.tree[id]
|
||||||
|
delete this.order[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = idx[idx.length - 1]; i < this.arr.length; i++) {
|
||||||
|
this.order[this.arr[i]] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeToDelSet = new Set(this.nodesToDel)
|
||||||
|
|
||||||
|
for (let k in this.tree) {
|
||||||
|
for (let ent of this.tree[k]) {
|
||||||
|
if (nodeToDelSet.has(ent)) {
|
||||||
|
this.tree[k].delete(ent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dfs(id) {
|
||||||
|
this.visited.add(id)
|
||||||
|
this.nodesToDel.push(id)
|
||||||
|
for (let x of this.tree[id]) {
|
||||||
|
if (!this.visited.has(x)) {
|
||||||
|
this.dfs(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const dt = new DepTree()
|
||||||
|
|
||||||
|
|
||||||
|
dt.addParent('r1')
|
||||||
|
dt.addParent('r2')
|
||||||
|
|
||||||
|
|
||||||
|
dt.addChild('r3', 'r1', 'r2')
|
||||||
|
|
||||||
|
dt.addParent('r4')
|
||||||
|
|
||||||
|
dt.addChild('r5', 'r4', 'r3')
|
||||||
|
|
||||||
|
dt.addChild('r6', 'r1', 'r5')
|
||||||
|
|
||||||
|
dt.addChild('r7', 'r3', 'r5')
|
||||||
|
|
||||||
|
|
||||||
|
// const x = dt.deleteNode('r3')
|
||||||
|
|
||||||
|
// console.log(x)
|
||||||
|
// console.log(dt.arr, dt.order)
|
||||||
|
|
||||||
|
// expectd output
|
||||||
|
// [ 6, 5, 4, 2 ]
|
||||||
|
// [ 'r1', 'r2', 'r4' ] { r1: 0, r2: 1, r4: 2 }
|
||||||
|
|
||||||
|
|
||||||
|
const x = dt.deleteNode('r5')
|
||||||
|
|
||||||
|
console.log(x)
|
||||||
|
console.log(dt.tree)
|
|
@ -0,0 +1,120 @@
|
||||||
|
export class DepTree {
|
||||||
|
constructor(obj) {
|
||||||
|
if (obj) {
|
||||||
|
console.log('load', obj)
|
||||||
|
this.order = { ...obj.order }
|
||||||
|
this.byId = { ...obj.byId }
|
||||||
|
this.allIds = [...obj.allIds]
|
||||||
|
|
||||||
|
this.tree = {}
|
||||||
|
for (let k in obj.tree) {
|
||||||
|
this.tree[k] = { ...obj.tree[k] }
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.tree = {}
|
||||||
|
this.order = {}
|
||||||
|
this.allIds = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addParent(id) {
|
||||||
|
if (this.tree[id]) return
|
||||||
|
this.tree[id] = {}
|
||||||
|
this.order[id] = this.allIds.length
|
||||||
|
this.allIds.push(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild(childId, ...parentIds) {
|
||||||
|
for (let parentId of parentIds) {
|
||||||
|
this.tree[parentId][childId] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addParent(childId)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
deleteNode(id) {
|
||||||
|
const dfs = (id) => {
|
||||||
|
visited.add(id)
|
||||||
|
nodesToDel.push(id)
|
||||||
|
for (let k in this.tree[id]) {
|
||||||
|
if (!visited.has(k)) {
|
||||||
|
dfs(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const visited = new Set()
|
||||||
|
|
||||||
|
const nodesToDel = []
|
||||||
|
dfs(id)
|
||||||
|
|
||||||
|
nodesToDel.sort((a, b) => this.order[b] - this.order[a])
|
||||||
|
|
||||||
|
|
||||||
|
let spliceIdx;
|
||||||
|
for (let id of nodesToDel) {
|
||||||
|
spliceIdx = this.order[id]
|
||||||
|
|
||||||
|
this.allIds.splice(spliceIdx, 1)
|
||||||
|
|
||||||
|
const deletedObj = sc.obj3d.children.splice(spliceIdx + 4, 1)[0]
|
||||||
|
|
||||||
|
deletedObj.traverse((obj)=>{
|
||||||
|
if (obj.geometry) obj.geometry.dispose()
|
||||||
|
if (obj.material) obj.material.dispose()
|
||||||
|
})
|
||||||
|
|
||||||
|
delete this.tree[id]
|
||||||
|
delete this.byId[id]
|
||||||
|
delete this.order[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = spliceIdx; i < this.allIds.length; i++) {
|
||||||
|
this.order[this.allIds[i]] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeToDelSet = new Set(nodesToDel)
|
||||||
|
for (let k in this.tree) {
|
||||||
|
for (let m in this.tree[k]) {
|
||||||
|
if (nodeToDelSet.has(m)) {
|
||||||
|
delete this.tree[k][m]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// const dt = new DepTree()
|
||||||
|
// dt.addParent('r1')
|
||||||
|
// dt.addParent('r2')
|
||||||
|
// dt.addChild('r3', 'r1', 'r2')
|
||||||
|
// dt.addParent('r4')
|
||||||
|
// dt.addChild('r5', 'r4', 'r3')
|
||||||
|
// dt.addChild('r6', 'r1', 'r5')
|
||||||
|
// dt.addChild('r7', 'r3', 'r5')
|
||||||
|
|
||||||
|
// dt.addParent('r8')
|
||||||
|
|
||||||
|
// // console.log(dt)
|
||||||
|
|
||||||
|
// // const x = dt.deleteNode('r3')
|
||||||
|
// // console.log(x)
|
||||||
|
// // console.log(dt.allIds, dt.order)
|
||||||
|
// // [ 6, 5, 4, 2 ]
|
||||||
|
// // [ 'r1', 'r2', 'r4' ] { r1: 0, r2: 1, r4: 2 }
|
||||||
|
|
||||||
|
|
||||||
|
// const x = dt.deleteNode('r5')
|
||||||
|
// console.log(dt)
|
||||||
|
// DepTree {
|
||||||
|
// tree: { r1: { r3: true }, r2: { r3: true }, r3: {}, r4: {}, r8: {} },
|
||||||
|
// order: { r1: 0, r2: 1, r3: 2, r4: 3, r8: 4 },
|
||||||
|
// allIds: [ 'r1', 'r2', 'r3', 'r4', 'r8' ]
|
||||||
|
// }
|
||||||
|
|
|
@ -98,7 +98,7 @@ export function extrude(sketch) {
|
||||||
this.render()
|
this.render()
|
||||||
|
|
||||||
// sketch.visible = false
|
// sketch.visible = false
|
||||||
this.store.dispatch({ type: 'rx-extrusion', mesh, sketch })
|
this.store.dispatch({ type: 'rx-extrusion', mesh, sketchId: sketch.obj3d.name })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
70
src/index.js
70
src/index.js
|
@ -2,43 +2,64 @@
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Root } from './app.jsx'
|
import { Root } from './app.jsx'
|
||||||
|
import update from 'immutability-helper';
|
||||||
|
|
||||||
import { createStore, applyMiddleware } from 'redux'
|
import { createStore, applyMiddleware } from 'redux'
|
||||||
import logger from 'redux-logger'
|
import logger from 'redux-logger'
|
||||||
|
|
||||||
let _entId = 0
|
import { DepTree } from './depTree.mjs'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function reducer(state = {}, action) {
|
function reducer(state = {}, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'rx-sketch':
|
case 'rx-sketch':
|
||||||
return {
|
return update(state, {
|
||||||
...state,
|
|
||||||
treeEntries: {
|
treeEntries: {
|
||||||
byNid: { ...state.treeEntries.byNid, [action.obj.obj3d.name]: action.obj },
|
byId: { [action.obj.obj3d.name]: { $set: action.obj } },
|
||||||
allNids: [...state.treeEntries.allNids, action.obj.obj3d.name]
|
allIds: { $push: [action.obj.obj3d.name] },
|
||||||
}
|
tree: { [action.obj.obj3d.name]: { $set: {} } },
|
||||||
}
|
order: { [action.obj.obj3d.name]: { $set: state.treeEntries.allIds.length } }
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
case 'set-active-sketch':
|
case 'set-active-sketch':
|
||||||
return {
|
return update(state, {
|
||||||
...state, activeSketchNid: action.sketch
|
activeSketchId: { $set: action.sketch },
|
||||||
}
|
})
|
||||||
case 'exit-sketch':
|
case 'exit-sketch':
|
||||||
return {
|
return {
|
||||||
...state, activeSketchNid: ''
|
...state, activeSketchId: ''
|
||||||
}
|
}
|
||||||
case 'rx-extrusion':
|
case 'rx-extrusion':
|
||||||
return {
|
|
||||||
...state,
|
return update(state, {
|
||||||
treeEntries: {
|
treeEntries: {
|
||||||
byNid: { ...state.treeEntries.byNid, [action.mesh.name]: action.mesh },
|
byId: {
|
||||||
allNids: [...state.treeEntries.allNids, action.mesh.name]
|
[action.mesh.name]: { $set: action.mesh }
|
||||||
},
|
},
|
||||||
mesh2sketch: {
|
allIds: { $push: [action.mesh.name] },
|
||||||
...state.mesh2sketch,
|
tree: {
|
||||||
[action.sketch.obj3d.name]: action.mesh.name
|
[action.sketchId]: { [action.mesh.name]: { $set: true } },
|
||||||
}
|
},
|
||||||
|
order: { [action.mesh.name]: { $set: state.treeEntries.allIds.length } }
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
case 'delete-node':
|
||||||
|
|
||||||
|
const depTree = new DepTree(state.treeEntries)
|
||||||
|
|
||||||
|
const obj = depTree.deleteNode(action.id)
|
||||||
|
|
||||||
|
|
||||||
|
return update(state, {
|
||||||
|
treeEntries: {$set: obj}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case 'restore-state':
|
case 'restore-state':
|
||||||
return action.state
|
return action.state
|
||||||
default:
|
default:
|
||||||
|
@ -48,12 +69,13 @@ function reducer(state = {}, action) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const preloadedState = {
|
const preloadedState = {
|
||||||
treeEntries: {
|
treeEntries: {
|
||||||
byNid: {},
|
byId: {},
|
||||||
allNids: []
|
allIds: [],
|
||||||
}
|
tree: {},
|
||||||
|
order: {},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { get3PtArc } from './drawArc'
|
||||||
import { _vec2, _vec3, raycaster, awaitPts } from '../utils/shared'
|
import { _vec2, _vec3, raycaster, awaitPts } from '../utils/shared'
|
||||||
import { replacer, reviver } from '../utils/mapJSONReplacer'
|
import { replacer, reviver } from '../utils/mapJSONReplacer'
|
||||||
import { AxesHelper } from '../utils/axes'
|
import { AxesHelper } from '../utils/axes'
|
||||||
import { drawDimension, _onMoveDimension, setDimLines } from './drawDimension';
|
import { drawDimension, _onMoveDimension, setDimLines, updateDim } from './drawDimension';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,6 +114,7 @@ class Sketch {
|
||||||
this.drawDimension = drawDimension.bind(this)
|
this.drawDimension = drawDimension.bind(this)
|
||||||
this._onMoveDimension = _onMoveDimension.bind(this)
|
this._onMoveDimension = _onMoveDimension.bind(this)
|
||||||
this.setDimLines = setDimLines.bind(this)
|
this.setDimLines = setDimLines.bind(this)
|
||||||
|
this.updateDim = updateDim.bind(this)
|
||||||
|
|
||||||
this.awaitPts = awaitPts.bind(this);
|
this.awaitPts = awaitPts.bind(this);
|
||||||
|
|
||||||
|
|
|
@ -87,29 +87,9 @@ export async function drawDimension() {
|
||||||
point.name = this.c_id
|
point.name = this.c_id
|
||||||
point.userData.type = 'dimension'
|
point.userData.type = 'dimension'
|
||||||
|
|
||||||
const updateDim = (c_id) => (ev_focus) => {
|
|
||||||
const value = ev_focus.target.textContent
|
|
||||||
console.log(value)
|
|
||||||
document.addEventListener('keydown', (e) => {
|
|
||||||
if (e.key == 'Enter') {
|
|
||||||
e.preventDefault()
|
|
||||||
const ent = this.constraints.get(c_id)
|
|
||||||
ent[1] = parseFloat(ev_focus.target.textContent)
|
|
||||||
this.constraints.set(c_id, ent)
|
|
||||||
this.updateOtherBuffers()
|
|
||||||
this.solve()
|
|
||||||
sc.render()
|
|
||||||
ev_focus.target.blur()
|
|
||||||
this.updateBoundingSpheres()
|
|
||||||
} else if (e.key == 'Escape') {
|
|
||||||
ev_focus.target.textContent = value
|
|
||||||
getSelection().empty()
|
|
||||||
ev_focus.target.blur()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
point.label.addEventListener('focus', updateDim(this.c_id))
|
|
||||||
|
point.label.addEventListener('focus', this.updateDim(this.c_id))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,12 +113,39 @@ const p2 = new THREE.Vector2()
|
||||||
const p3 = new THREE.Vector2()
|
const p3 = new THREE.Vector2()
|
||||||
let dir, hyp, proj, perp, p1e, p2e, nids, _p1, _p2;
|
let dir, hyp, proj, perp, p1e, p2e, nids, _p1, _p2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function updateDim(c_id) {
|
||||||
|
return (ev_focus) => {
|
||||||
|
const value = ev_focus.target.textContent
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key == 'Enter') {
|
||||||
|
e.preventDefault()
|
||||||
|
const ent = this.constraints.get(c_id)
|
||||||
|
ent[1] = parseFloat(ev_focus.target.textContent)
|
||||||
|
this.constraints.set(c_id, ent)
|
||||||
|
this.updateOtherBuffers()
|
||||||
|
this.solve()
|
||||||
|
sc.render()
|
||||||
|
ev_focus.target.blur()
|
||||||
|
this.updateBoundingSpheres()
|
||||||
|
} else if (e.key == 'Escape') {
|
||||||
|
ev_focus.target.textContent = value
|
||||||
|
getSelection().empty()
|
||||||
|
ev_focus.target.blur()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function _onMoveDimension(point, line) {
|
export function _onMoveDimension(point, line) {
|
||||||
|
|
||||||
nids = line.userData.nids
|
nids = line.userData.nids
|
||||||
|
|
||||||
_p1 = this.obj3d.children[sketcher.objIdx.get(nids[0])].geometry.attributes.position.array
|
_p1 = this.obj3d.children[this.objIdx.get(nids[0])].geometry.attributes.position.array
|
||||||
_p2 = this.obj3d.children[sketcher.objIdx.get(nids[1])].geometry.attributes.position.array
|
_p2 = this.obj3d.children[this.objIdx.get(nids[1])].geometry.attributes.position.array
|
||||||
|
|
||||||
p1.set(_p1[0], _p1[1])
|
p1.set(_p1[0], _p1[1])
|
||||||
p2.set(_p2[0], _p2[1])
|
p2.set(_p2[0], _p2[1])
|
||||||
|
@ -163,27 +170,6 @@ export function _onMoveDimension(point, line) {
|
||||||
|
|
||||||
|
|
||||||
export function setDimLines() {
|
export function setDimLines() {
|
||||||
const updateDim = (c_id) => (ev_focus) => {
|
|
||||||
const value = ev_focus.target.textContent
|
|
||||||
console.log(value)
|
|
||||||
document.addEventListener('keydown', (e) => {
|
|
||||||
if (e.key == 'Enter') {
|
|
||||||
e.preventDefault()
|
|
||||||
const ent = this.constraints.get(c_id)
|
|
||||||
ent[1] = parseFloat(ev_focus.target.textContent)
|
|
||||||
this.constraints.set(c_id, ent)
|
|
||||||
this.updateOtherBuffers()
|
|
||||||
this.solve()
|
|
||||||
sc.render()
|
|
||||||
ev_focus.target.blur()
|
|
||||||
this.updateBoundingSpheres()
|
|
||||||
} else if (e.key == 'Escape') {
|
|
||||||
ev_focus.target.textContent = value
|
|
||||||
getSelection().empty()
|
|
||||||
ev_focus.target.blur()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const restoreLabels = this.labelContainer.childElementCount == 0;
|
const restoreLabels = this.labelContainer.childElementCount == 0;
|
||||||
|
|
||||||
|
@ -201,17 +187,14 @@ export function setDimLines() {
|
||||||
point.label.contentEditable = true;
|
point.label.contentEditable = true;
|
||||||
this.labelContainer.append(point.label)
|
this.labelContainer.append(point.label)
|
||||||
|
|
||||||
|
point.label.addEventListener('focus', this.updateDim(this.c_id))
|
||||||
|
|
||||||
point.label.addEventListener('focus', updateDim(this.c_id))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
nids = dims[i].userData.nids
|
nids = dims[i].userData.nids
|
||||||
|
|
||||||
_p1 = this.obj3d.children[sketcher.objIdx.get(nids[0])].geometry.attributes.position.array
|
_p1 = this.obj3d.children[this.objIdx.get(nids[0])].geometry.attributes.position.array
|
||||||
_p2 = this.obj3d.children[sketcher.objIdx.get(nids[1])].geometry.attributes.position.array
|
_p2 = this.obj3d.children[this.objIdx.get(nids[1])].geometry.attributes.position.array
|
||||||
|
|
||||||
const offset = dims[i + 1].userData.offset
|
const offset = dims[i + 1].userData.offset
|
||||||
|
|
||||||
|
|
|
@ -13,20 +13,11 @@ export function onHover(e) {
|
||||||
);
|
);
|
||||||
|
|
||||||
let hoverPts;
|
let hoverPts;
|
||||||
|
let idx = []
|
||||||
|
|
||||||
if (this.obj3d.userData.type == 'sketch') {
|
if (this.obj3d.userData.type == 'sketch') {
|
||||||
hoverPts = raycaster.intersectObjects([...this.obj3d.children[1].children, ...this.obj3d.children])
|
hoverPts = raycaster.intersectObjects([...this.obj3d.children[1].children, ...this.obj3d.children])
|
||||||
|
|
||||||
// if (!hoverPts.length) {
|
|
||||||
// hoverPts = raycaster.intersectObjects(this.obj3d.children)
|
|
||||||
// }
|
|
||||||
} else {
|
|
||||||
hoverPts = raycaster.intersectObjects(this.obj3d.children, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (hoverDim.length) {
|
|
||||||
// }
|
|
||||||
|
|
||||||
let idx = []
|
|
||||||
if (hoverPts.length) {
|
if (hoverPts.length) {
|
||||||
let minDist = Infinity;
|
let minDist = Infinity;
|
||||||
for (let i = 0; i < hoverPts.length; i++) {
|
for (let i = 0; i < hoverPts.length; i++) {
|
||||||
|
@ -42,6 +33,31 @@ export function onHover(e) {
|
||||||
if (!idx.length) idx.push(0)
|
if (!idx.length) idx.push(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// hoverPts = raycaster.intersectObjects(this.obj3d.children)
|
||||||
|
hoverPts = raycaster.intersectObjects(this.obj3d.children,true)
|
||||||
|
|
||||||
|
|
||||||
|
// for (let i = 0; i < hoverPts.length; i++) {
|
||||||
|
// const obj = hoverPts[i].object
|
||||||
|
// if (obj.userData.type == "mesh" && obj.visible || obj.userData.type == "plane") {
|
||||||
|
// idx.push(i)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if (hoverPts.length) {
|
||||||
|
// console.log(hoverPts)
|
||||||
|
if (!idx.length) idx.push(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (idx.length) { // after filtering, hovered objs still exists
|
if (idx.length) { // after filtering, hovered objs still exists
|
||||||
if (hoverPts[idx[0]].object != this.hovered[0]) { // if the previous hovered obj is not the same as current
|
if (hoverPts[idx[0]].object != this.hovered[0]) { // if the previous hovered obj is not the same as current
|
||||||
|
|
||||||
|
|
26
todo.txt
26
todo.txt
|
@ -1,11 +1,31 @@
|
||||||
fix css on design tree (a lot of work) \
|
fix css on design tree (a lot of work) \
|
||||||
clear dim on exit exit sketch / rehydrate when back or after loading
|
clear dim on exit exit sketch / rehydrate when back or after loading \\\ done
|
||||||
boolean flesh out refresh / replace mesh
|
|
||||||
dimension to origin
|
boolean flesh out refresh / replace mesh / delete mesh
|
||||||
|
- need to auto hide ( consume) when new boolean created
|
||||||
|
- create derived part using relationship as name
|
||||||
|
- sensible default names, like extrude 1, sketch 1, leverage react for this
|
||||||
|
- hidden bodies messes up hover highlight
|
||||||
|
|
||||||
|
extrude edit dialog. directio and magnitude
|
||||||
|
|
||||||
fix extrusion loop find
|
fix extrusion loop find
|
||||||
|
|
||||||
|
dimension to origin
|
||||||
|
|
||||||
reattaching sketch
|
reattaching sketch
|
||||||
file save
|
file save
|
||||||
stl export
|
stl export
|
||||||
|
|
||||||
angle
|
angle
|
||||||
other constraints / sprite
|
other constraints / sprite
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
finish mode messed up after restore
|
Loading…
Reference in New Issue