workiing file expoort
This commit is contained in:
parent
4076c90e58
commit
4e0706211f
10
src/Scene.js
10
src/Scene.js
@ -15,10 +15,14 @@ import { AxesHelper } from './axes'
|
|||||||
|
|
||||||
import CSG from "../lib/three-csg"
|
import CSG from "../lib/three-csg"
|
||||||
|
|
||||||
|
import { STLExporter } from '../node_modules/three/examples/jsm/exporters/STLExporter'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
window.loader = new THREE.ObjectLoader();
|
window.loader = new THREE.ObjectLoader();
|
||||||
|
window.STLexp = new STLExporter();
|
||||||
|
|
||||||
window.id = 0
|
window.id = 0
|
||||||
window.sid = 1
|
window.sid = 1
|
||||||
window.mid = 1
|
window.mid = 1
|
||||||
@ -174,6 +178,10 @@ export class Scene {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveString() {
|
||||||
|
return JSON.stringify([id, this.sid, this.mid, this.store.getState().treeEntries])
|
||||||
|
}
|
||||||
|
|
||||||
loadState() { //uglyyy
|
loadState() { //uglyyy
|
||||||
const [curid, cursid, curmid, state] = JSON.parse(
|
const [curid, cursid, curmid, state] = JSON.parse(
|
||||||
localStorage.getItem('sv2')
|
localStorage.getItem('sv2')
|
||||||
@ -218,7 +226,7 @@ export class Scene {
|
|||||||
let entry = JSON.parse(string)
|
let entry = JSON.parse(string)
|
||||||
entry.obj3d = loader.parse(entry.obj3d)
|
entry.obj3d = loader.parse(entry.obj3d)
|
||||||
|
|
||||||
this.obj3d.add(entry.obj3d)
|
// this.obj3d.add(entry.obj3d)
|
||||||
|
|
||||||
entry = new Sketch(this, entry)
|
entry = new Sketch(this, entry)
|
||||||
entry.obj3d.addEventListener('change', this.render)
|
entry.obj3d.addEventListener('change', this.render)
|
||||||
|
@ -175,9 +175,9 @@ class Sketch {
|
|||||||
// overkill but good solution if this check was more costly
|
// overkill but good solution if this check was more costly
|
||||||
this.hasChanged = false
|
this.hasChanged = false
|
||||||
this.idOnActivate = id
|
this.idOnActivate = id
|
||||||
|
this.c_idOnActivate = this.c_id
|
||||||
// console.log(this,this.selected)
|
// console.log(this,this.selected)
|
||||||
const changeDetector = (e) => {
|
const changeDetector = (e) => {
|
||||||
console.log(this.selected.length, e.buttons)
|
|
||||||
if (this.selected.length && e.buttons) {
|
if (this.selected.length && e.buttons) {
|
||||||
this.canvas.removeEventListener('pointermove', changeDetector)
|
this.canvas.removeEventListener('pointermove', changeDetector)
|
||||||
this.hasChanged = true
|
this.hasChanged = true
|
||||||
@ -187,11 +187,10 @@ class Sketch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deactivate() {
|
deactivate() {
|
||||||
console.log('deactivateeeeeeee')
|
|
||||||
window.removeEventListener('keydown', this.onKeyPress)
|
window.removeEventListener('keydown', this.onKeyPress)
|
||||||
this.canvas.removeEventListener('pointerdown', this.onPick)
|
this.canvas.removeEventListener('pointerdown', this.onPick)
|
||||||
this.canvas.removeEventListener('pointermove', this.onHover)
|
this.canvas.removeEventListener('pointermove', this.onHover)
|
||||||
this.store.dispatch({ type: 'finish-sketch' })
|
|
||||||
this.labelContainer.innerHTML = ""
|
this.labelContainer.innerHTML = ""
|
||||||
this.obj3d.visible = false
|
this.obj3d.visible = false
|
||||||
this.obj3d.traverse(e => e.layers.disable(2))
|
this.obj3d.traverse(e => e.layers.disable(2))
|
||||||
|
@ -116,6 +116,7 @@ export function extrude(sketch, depth, refresh=false) {
|
|||||||
this.store.dispatch({ type: 'rx-extrusion', mesh, sketchId: sketch.obj3d.name })
|
this.store.dispatch({ type: 'rx-extrusion', mesh, sketchId: sketch.obj3d.name })
|
||||||
|
|
||||||
if (this.activeSketch == sketch) {
|
if (this.activeSketch == sketch) {
|
||||||
|
this.store.dispatch({ type: 'finish-sketch' })
|
||||||
sketch.deactivate()
|
sketch.deactivate()
|
||||||
}
|
}
|
||||||
this.render()
|
this.render()
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
|
|
||||||
|
|
||||||
import React, { useEffect, useReducer, useRef, useState } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import { MdDone, MdClose } from 'react-icons/md'
|
import { MdDone, MdClose } from 'react-icons/md'
|
||||||
import * as Icon from "./icons";
|
import * as Icon from "./icons";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const Dialog = () => {
|
export const Dialog = () => {
|
||||||
|
|
||||||
const dialog = useSelector(state => state.ui.dialog)
|
const dialog = useSelector(state => state.ui.dialog)
|
||||||
@ -17,6 +15,7 @@ export const Dialog = () => {
|
|||||||
const ref = useRef()
|
const ref = useRef()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log(dialog)
|
||||||
if (!ref.current) return
|
if (!ref.current) return
|
||||||
ref.current.focus()
|
ref.current.focus()
|
||||||
}, [dialog])
|
}, [dialog])
|
||||||
@ -29,7 +28,18 @@ export const Dialog = () => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
const extrudeEdit = () => {
|
||||||
|
|
||||||
|
|
||||||
|
dialog.target.userData.featureInfo[1] = ref.current.value
|
||||||
|
|
||||||
|
sc.refreshNode(dialog.target.name)
|
||||||
|
|
||||||
|
sc.render()
|
||||||
|
dispatch({ type: "clear-dialog" })
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
switch (dialog.action) {
|
switch (dialog.action) {
|
||||||
case 'extrude':
|
case 'extrude':
|
||||||
@ -46,44 +56,54 @@ export const Dialog = () => {
|
|||||||
onClick={() => dispatch({ type: "clear-dialog" })}
|
onClick={() => dispatch({ type: "clear-dialog" })}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
case 'extrude-edit':
|
||||||
|
return <>
|
||||||
|
<input className='w-16 border-t-0 border-l-0 border-r-0 border-b border-gray-50 text-gray-50 mr-6' type="number" defaultValue={dialog.target.userData.featureInfo[1]} step="0.1" ref={ref} />
|
||||||
|
<Icon.Flip className="btn w-auto h-full p-3.5"
|
||||||
|
onClick={() => ref.current.value *= -1}
|
||||||
|
/>
|
||||||
|
<MdDone
|
||||||
|
className="btn w-auto h-full p-3.5"
|
||||||
|
onClick={extrudeEdit}
|
||||||
|
/>
|
||||||
|
<MdClose className="btn w-auto h-full p-3.5 mr-6"
|
||||||
|
onClick={() => dispatch({ type: "clear-dialog" })}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
case 'sketch':
|
case 'sketch':
|
||||||
return <>
|
return <>
|
||||||
<MdDone
|
<MdDone
|
||||||
className="btn w-auto h-full p-3.5"
|
className="btn w-auto h-full p-3.5"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (sc.activeSketch.hasChanged || sc.activeSketch.idOnActivate != id) {
|
if (sc.activeSketch.hasChanged
|
||||||
|
|| sc.activeSketch.idOnActivate != id
|
||||||
// for (let k in sc.store.getState().treeEntries.tree[sc.activeSketch.obj3d.name]) {
|
|| sc.activeSketch.c_idOnActivate != sc.activeSketch.c_id
|
||||||
// console.log('circlllles',k)
|
) {
|
||||||
// }
|
|
||||||
|
|
||||||
sc.refreshNode(sc.activeSketch.obj3d.name)
|
sc.refreshNode(sc.activeSketch.obj3d.name)
|
||||||
}
|
}
|
||||||
// dispatch({ type: 'update-descendents', sketch})
|
|
||||||
|
dispatch({ type: 'finish-sketch' })
|
||||||
|
|
||||||
sc.activeSketch.deactivate()
|
sc.activeSketch.deactivate()
|
||||||
sc.render()
|
sc.render()
|
||||||
|
|
||||||
dispatch({ type: "clear-dialog" })
|
dispatch({ type: "clear-dialog" })
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<MdClose className="btn w-auto h-full p-3.5 mr-6"
|
<MdClose className="btn w-auto h-full p-3.5 mr-6"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
console.log('cancle',sc.activeSketch.hasChanged, sc.activeSketch.idOnActivate, id)
|
if (sc.activeSketch.hasChanged
|
||||||
if (sc.activeSketch.hasChanged || sc.activeSketch.idOnActivate != id) {
|
|| sc.activeSketch.idOnActivate != id
|
||||||
console.log('has changed')
|
|| sc.activeSketch.c_idOnActivate != sc.activeSketch.c_id
|
||||||
dispatch({ type: "cancel-sketch" })
|
) {
|
||||||
sc.store.getState().treeEntries.byId[sc.activeSketch.obj3d.name].deactivate()
|
dispatch({ type: "restore-sketch" })
|
||||||
} else {
|
} else {
|
||||||
|
dispatch({ type: 'finish-sketch' })
|
||||||
|
}
|
||||||
|
|
||||||
sc.activeSketch.deactivate()
|
sc.activeSketch.deactivate()
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sc.render()
|
sc.render()
|
||||||
dispatch({ type: "clear-dialog" })
|
dispatch({ type: "clear-dialog" })
|
||||||
|
}}
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
default:
|
default:
|
||||||
|
39
src/react/fileExporter.js
Normal file
39
src/react/fileExporter.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
const link = document.createElement( 'a' );
|
||||||
|
link.style.display = 'none';
|
||||||
|
document.body.appendChild( link );
|
||||||
|
|
||||||
|
function save(blob, filename) {
|
||||||
|
|
||||||
|
link.href = URL.createObjectURL(blob);
|
||||||
|
link.download = filename;
|
||||||
|
link.click();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function saveArrayBuffer( buffer, filename ) {
|
||||||
|
|
||||||
|
save( new Blob( [ buffer ], { type: 'application/octet-stream' } ), filename );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveString( text, filename ) {
|
||||||
|
|
||||||
|
save( new Blob( [ text ], { type: 'text/plain' } ), filename );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function STLExport() {
|
||||||
|
if (sc.selected[0] && sc.selected[0].userData.type == 'mesh') {
|
||||||
|
const result = STLexp.parse( sc.selected[0], { binary: true } );
|
||||||
|
saveArrayBuffer( result, 'box.stl' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function savePart() {
|
||||||
|
const string = sc.saveString()
|
||||||
|
|
||||||
|
saveString( LZString.compress(string), 'test2.bin' );
|
||||||
|
|
||||||
|
}
|
@ -5,11 +5,35 @@ import React, { useEffect, useReducer } from 'react';
|
|||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
|
||||||
import { FaEdit } from 'react-icons/fa'
|
import { FaEdit } from 'react-icons/fa'
|
||||||
import { MdSave, MdFolder } from 'react-icons/md'
|
import { MdSave } from 'react-icons/md'
|
||||||
import { FaFolderOpen } from 'react-icons/fa'
|
import { FaFolderOpen } from 'react-icons/fa'
|
||||||
|
|
||||||
import * as Icon from "./icons";
|
import * as Icon from "./icons";
|
||||||
import { Dialog } from './dialog'
|
import { Dialog } from './dialog'
|
||||||
|
import { STLExport, savePart } from './fileExporter'
|
||||||
|
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.style.display = 'none';
|
||||||
|
document.body.appendChild(link);
|
||||||
|
|
||||||
|
function save(blob, filename) {
|
||||||
|
|
||||||
|
link.href = URL.createObjectURL(blob);
|
||||||
|
link.download = filename;
|
||||||
|
link.click();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function saveArrayBuffer(buffer, filename) {
|
||||||
|
|
||||||
|
save(new Blob([buffer], { type: 'application/octet-stream' }), filename);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const NavBar = () => {
|
export const NavBar = () => {
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
@ -44,8 +68,9 @@ export const NavBar = () => {
|
|||||||
|
|
||||||
const sketchModeButtons = [
|
const sketchModeButtons = [
|
||||||
[Icon.Extrude, () => {
|
[Icon.Extrude, () => {
|
||||||
sc.activeSketch.deactivate()
|
dispatch({ type: 'finish-sketch' })
|
||||||
dispatch({ type: 'set-dialog', action: 'extrude', target: sc.activeSketch })
|
dispatch({ type: 'set-dialog', action: 'extrude', target: sc.activeSketch })
|
||||||
|
|
||||||
}, 'Extrude [e]'],
|
}, 'Extrude [e]'],
|
||||||
[Icon.Dimension, () => sc.activeSketch.command('d'), 'Dimension [d]'],
|
[Icon.Dimension, () => sc.activeSketch.command('d'), 'Dimension [d]'],
|
||||||
[Icon.Line, () => sc.activeSketch.command('l'), 'Line [l]'],
|
[Icon.Line, () => sc.activeSketch.command('l'), 'Line [l]'],
|
||||||
@ -66,9 +91,9 @@ export const NavBar = () => {
|
|||||||
[Icon.Union, () => boolOp('u'), 'Union'],
|
[Icon.Union, () => boolOp('u'), 'Union'],
|
||||||
[Icon.Subtract, () => boolOp('s'), 'Subtract'],
|
[Icon.Subtract, () => boolOp('s'), 'Subtract'],
|
||||||
[Icon.Intersect, () => boolOp('i'), 'Intersect'],
|
[Icon.Intersect, () => boolOp('i'), 'Intersect'],
|
||||||
[MdSave, () => boolOp('i'), 'Save [ctrl+s]'],
|
[MdSave, savePart, 'Save [ctrl+s]'],
|
||||||
[FaFolderOpen, () => boolOp('i'), 'Load'],
|
[FaFolderOpen, () => boolOp('i'), 'Load'],
|
||||||
[Icon.Stl, () => boolOp('i'), 'Export STL'],
|
[Icon.Stl, STLExport, 'Export STL'],
|
||||||
]
|
]
|
||||||
|
|
||||||
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
||||||
|
@ -43,21 +43,20 @@ export function treeEntries(state = defaultState, action) {
|
|||||||
activeSketchId: { $set: "" },
|
activeSketchId: { $set: "" },
|
||||||
visible: { [state.activeSketchId]: { $set: false } },
|
visible: { [state.activeSketchId]: { $set: false } },
|
||||||
})
|
})
|
||||||
case 'cancel-sketch':
|
case 'restore-sketch':
|
||||||
|
|
||||||
const sketch = sc.loadSketch(cache)
|
const sketch = sc.loadSketch(cache)
|
||||||
|
|
||||||
const deletedObj = sc.obj3d.children.splice(state.order[state.activeSketchId] + 1, 1,
|
const deletedObj = sc.obj3d.children.splice(state.order[state.activeSketchId] + 1, 1,
|
||||||
sketch.obj3d
|
sketch.obj3d
|
||||||
)[0]
|
)[0]
|
||||||
console.log('spliced and starting to delete')
|
|
||||||
|
|
||||||
deletedObj.traverse((obj) => {
|
deletedObj.traverse((obj) => {
|
||||||
if (obj.geometry) obj.geometry.dispose()
|
if (obj.geometry) obj.geometry.dispose()
|
||||||
if (obj.material) obj.material.dispose()
|
if (obj.material) obj.material.dispose()
|
||||||
})
|
})
|
||||||
|
|
||||||
// sketch.deactivate()
|
sc.activeSketch = sketch
|
||||||
|
|
||||||
return update(state, {
|
return update(state, {
|
||||||
activeSketchId: { $set: "" },
|
activeSketchId: { $set: "" },
|
||||||
|
@ -28,19 +28,18 @@ const TreeEntry = ({ entId }) => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const state = useSelector(state => state.treeEntries)
|
const treeEntriesById = useSelector(state => state.treeEntries.byId)
|
||||||
const treeEntries = useSelector(state => state.treeEntries.byId)
|
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
const visible = useSelector(state => state.treeEntries.visible[entId])
|
const visible = useSelector(state => state.treeEntries.visible[entId])
|
||||||
|
|
||||||
let obj3d, sketch;
|
let obj3d, sketch;
|
||||||
|
|
||||||
if (treeEntries[entId].obj3d) {
|
if (treeEntriesById[entId].obj3d) {
|
||||||
obj3d = treeEntries[entId].obj3d
|
obj3d = treeEntriesById[entId].obj3d
|
||||||
sketch = treeEntries[entId]
|
sketch = treeEntriesById[entId]
|
||||||
} else {
|
} else {
|
||||||
obj3d = treeEntries[entId]
|
obj3d = treeEntriesById[entId]
|
||||||
}
|
}
|
||||||
let Icon = treeIcons[obj3d.userData.type]
|
let Icon = treeIcons[obj3d.userData.type]
|
||||||
|
|
||||||
@ -50,14 +49,17 @@ const TreeEntry = ({ entId }) => {
|
|||||||
return <div className='btn select-none flex justify-start w-full h-7 items-center text-sm'
|
return <div className='btn select-none flex justify-start w-full h-7 items-center text-sm'
|
||||||
onDoubleClick={() => {
|
onDoubleClick={() => {
|
||||||
if (obj3d.userData.type == 'sketch') {
|
if (obj3d.userData.type == 'sketch') {
|
||||||
sc.activeSketch && sc.activeSketch.deactivate()
|
if (sc.activeSketch) {
|
||||||
|
dispatch({ type: 'finish-sketch' })
|
||||||
|
sc.activeSketch.deactivate()
|
||||||
|
}
|
||||||
sketch.activate()
|
sketch.activate()
|
||||||
|
|
||||||
sc.clearSelection()
|
sc.clearSelection()
|
||||||
sc.activeSketch = sketch;
|
sc.activeSketch = sketch;
|
||||||
dispatch({ type: 'set-dialog', action: 'sketch' })
|
dispatch({ type: 'set-dialog', action: 'sketch' })
|
||||||
sc.render()
|
sc.render()
|
||||||
|
} else if (obj3d.userData.featureInfo.length == 2) {
|
||||||
|
dispatch({ type: 'set-dialog', action: 'extrude-edit', target: treeEntriesById[entId] })
|
||||||
}
|
}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
@ -116,14 +118,14 @@ const TreeEntry = ({ entId }) => {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<MdRefresh className='btn-green h-full w-auto p-1.5'
|
{/* <MdRefresh className='btn-green h-full w-auto p-1.5'
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
sc.refreshNode(entId)
|
sc.refreshNode(entId)
|
||||||
sc.render()
|
sc.render()
|
||||||
}}
|
}}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
{
|
{
|
||||||
visible ?
|
visible ?
|
||||||
|
16
todo.txt
16
todo.txt
@ -32,28 +32,36 @@ extrude dialogue / done
|
|||||||
better default ent names / done
|
better default ent names / done
|
||||||
loopfind especially arc, // fixed for single looop, good enough, maybe stretch goal of selecting search start pt
|
loopfind especially arc, // fixed for single looop, good enough, maybe stretch goal of selecting search start pt
|
||||||
dim tag delete //resolved
|
dim tag delete //resolved
|
||||||
|
auto update extrude // done
|
||||||
|
extrude edit dialog // done
|
||||||
|
|
||||||
|
|
||||||
|
-sometimes unable to hit return and change dimensionk
|
||||||
-unable to delete arc
|
-unable to delete arc
|
||||||
hover not clearing sometimes in sketch
|
hover not clearing sometimes in sketch
|
||||||
|
0.000 artifact
|
||||||
|
|
||||||
|
|
||||||
auto update extrude
|
|
||||||
file save, stl export
|
file save, stl export
|
||||||
|
|
||||||
|
reattach sketch
|
||||||
|
|
||||||
|
highlight button to indicate active mode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
add cancle soft button for line arc
|
add cancle soft button for line arc
|
||||||
|
|
||||||
reattach sketch
|
|
||||||
|
|
||||||
auto snap
|
auto snap
|
||||||
constraint labels,equal
|
constraint labels,equal
|
||||||
parallel
|
|
||||||
|
parallel // need to add antoher button to feature ,or empty placeholder
|
||||||
|
|
||||||
|
|
||||||
tree relation tool tip
|
tree relation tool tip
|
||||||
tree ent renaming
|
tree ent renaming
|
||||||
|
vertical and horzontal baseline to dimension to
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user