workiing file expoort

master
howard 2021-04-17 06:32:14 -07:00
parent 4076c90e58
commit 4e0706211f
9 changed files with 151 additions and 50 deletions

View File

@ -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
@ -173,6 +177,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(
@ -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)

View File

@ -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))

View File

@ -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()

View File

@ -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
View 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' );
}

View File

@ -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);

View File

@ -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: "" },

View File

@ -11,7 +11,7 @@ export const Tree = () => {
return <div className='sideNav flex flex-col bg-gray-800'> return <div className='sideNav flex flex-col bg-gray-800'>
{treeEntries.allIds.map((entId, idx) => ( {treeEntries.allIds.map((entId, idx) => (
<TreeEntry key={idx} entId={entId}/> <TreeEntry key={idx} entId={entId} />
))} ))}
</div> </div>
@ -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 ?

View File

@ -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