diff --git a/icon/svgr_raw/arc.svg b/icon/svgr_raw/arc.svg index 675f63c..e78e48e 100644 --- a/icon/svgr_raw/arc.svg +++ b/icon/svgr_raw/arc.svg @@ -23,22 +23,23 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="20.540932" - inkscape:cx="3.3726703" - inkscape:cy="-0.099609255" + inkscape:zoom="10.270466" + inkscape:cx="-9.1074268" + inkscape:cy="19.96038" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:document-rotation="0" showgrid="false" inkscape:window-width="1514" inkscape:window-height="1199" - inkscape:window-x="1031" - inkscape:window-y="111" + inkscape:window-x="550" + inkscape:window-y="74" inkscape:window-maximized="0" units="px" inkscape:snap-object-midpoints="true" inkscape:snap-text-baseline="true" - inkscape:snap-center="true" /> + inkscape:snap-center="true" + inkscape:snap-global="false" /> @@ -60,34 +61,64 @@ id="path1525" sodipodi:type="arc" sodipodi:cx="1.75" - sodipodi:cy="13.631019" + sodipodi:cy="14.25" sodipodi:rx="12.5" sodipodi:ry="12.5" - sodipodi:start="5.2879172" - sodipodi:end="6.1912839" + sodipodi:start="4.8869219" + sodipodi:end="5.2708943" sodipodi:arc-type="arc" - d="M 8.5534749,3.1447071 A 12.5,12.5 0 0 1 14.19725,12.483867" + d="M 3.9206022,1.9399031 A 12.5,12.5 0 0 1 8.3739904,3.6493985" sodipodi:open="true" /> - + x="0.75" + y="0.75" /> + y="13.25" /> + + + + diff --git a/icon/svgr_raw/line.svg b/icon/svgr_raw/line.svg index 57d6ad2..617fc4b 100644 --- a/icon/svgr_raw/line.svg +++ b/icon/svgr_raw/line.svg @@ -13,7 +13,7 @@ version="1.1" id="svg2112" inkscape:version="1.0.2 (1.0.2+r75+1)" - sodipodi:docname="line.svg"> + sodipodi:docname="line_alt.svg"> image/svg+xml - + @@ -57,7 +57,7 @@ id="layer1"> + y="4" /> + y="10" /> + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/Scene.js b/src/Scene.js index be14a51..a284d0d 100644 --- a/src/Scene.js +++ b/src/Scene.js @@ -441,7 +441,7 @@ async function addSketch() { } window.sc = new Scene(store) -sc.loadState() +// sc.loadState() // sc.camera.layers.enable(1) // rc.layers.set(1) \ No newline at end of file diff --git a/src/Sketch.js b/src/Sketch.js index 01bc2b0..6d2e89c 100644 --- a/src/Sketch.js +++ b/src/Sketch.js @@ -4,9 +4,9 @@ import * as THREE from '../node_modules/three/src/Three'; import { _vec2, _vec3, raycaster, awaitSelection, ptObj } from './shared' -import { drawOnClick1, drawOnClick2, drawPreClick2, drawClear, drawPoint } from './drawEvents' +import { drawOnClick1, drawOnClick2, drawPreClick2, drawOnClick3, drawPreClick3, drawClear, drawPoint } from './drawEvents' import { onHover, onDrag, onPick, onRelease } from './mouseEvents' -import { setCoincident, setOrdinate } from './constraintEvents' +import { setCoincident, setOrdinate, setTangent } from './constraintEvents' import { get3PtArc } from './drawArc' import { replacer, reviver } from './utils' import { AxesHelper } from './sketchAxes' @@ -127,6 +127,9 @@ class Sketch { this.drawPreClick2 = drawPreClick2.bind(this); this.drawOnClick2 = drawOnClick2.bind(this); + this.drawPreClick3 = drawPreClick3.bind(this); + this.drawOnClick3 = drawOnClick3.bind(this); + this.drawDimension = drawDimension.bind(this) this._onMoveDimension = _onMoveDimension.bind(this) this.setDimLines = setDimLines.bind(this) @@ -202,13 +205,13 @@ class Sketch { onKeyPress(e) { switch (e.key) { case 'Escape': - drawClear.bind(this)() + drawClear.call(this) this.mode = "" document.activeElement.blur() break; case 'l': if (this.mode == 'line') { - drawClear.bind(this)() + drawClear.call(this) } this.canvas.addEventListener('pointerdown', this.drawOnClick1) this.mode = "line" @@ -243,7 +246,10 @@ class Sketch { setOrdinate.call(this, 1) this.mode = "" break; - + case 't': + setTangent.call(this) + this.mode = "" + break; case 'z': var string = JSON.stringify(this.toJSON()); window.string = string; @@ -340,7 +346,7 @@ class Sketch { this.constraintsBuf.set( [ this.constraintNum[obj[0]], obj[1], - ...obj[2].map(ele => this.objIdx.get(ele) ?? -1), + ...obj[2].map(ele => this.objIdx.get(ele) ?? 0), ], (i) * 6 ) @@ -459,7 +465,9 @@ class Sketch { if (obj[0] != 'arc') continue; const [p1, p2, c, arc] = obj[1].map(e => this.obj3d.children[this.objIdx.get(e)]) - const points = get3PtArc( + let points + + points = get3PtArc( p1.geometry.attributes.position.array, p2.geometry.attributes.position.array, c.geometry.attributes.position.array @@ -469,15 +477,10 @@ class Sketch { arc.needsUpdate = true; } - this.setDimLines() - // this.setAngLines() - - // this.obj3d.dispatchEvent({ type: 'change' }) } - } const _m1 = new THREE.Matrix4() diff --git a/src/constraintEvents.js b/src/constraintEvents.js index 4081348..dca0e3f 100644 --- a/src/constraintEvents.js +++ b/src/constraintEvents.js @@ -1,4 +1,4 @@ -import {color} from './shared' +import { color } from './shared' export async function setCoincident() { let selection = await this.awaitSelection({ point: 2 }, { point: 1, line: 1 }) @@ -12,12 +12,15 @@ export async function setCoincident() { ) } else { const idx = selection[0].userData.type == 'point' ? [0, 1] : [1, 0] + this.constraints.set(++this.c_id, [ - 'pt_on_line', -1, + selection[idx[1]].userData.ccw !== undefined ? 'pt_on_circle' : 'pt_on_line' + , -1, [selection[idx[0]].name, -1, selection[idx[1]].name, -1] /////// ] ) + } selection[1].userData.constraints.push(this.c_id) @@ -37,17 +40,63 @@ export async function setCoincident() { } -export function setOrdinate(dir = 0) { +export async function setOrdinate(dir = 0) { + let selection = await this.awaitSelection({ point: 2 }, { line: 1 }) + if (selection == null) return; + let arr + if (this.selected.length == 1) { + arr = [-1, -1, selection[0].name, -1] + } else { + arr = [selection[0].name, selection[1].name, -1, -1] + } - const line = this.selected[0] this.constraints.set(++this.c_id, [ dir ? 'vertical' : 'horizontal', -1, - [-1, -1, line.name, -1] /////// + arr ] ) - line.userData.constraints.push(this.c_id) + selection.forEach(element => { + element.userData.constraints.push(this.c_id) + }); + + + this.updateOtherBuffers() + this.solve() + this.updateBoundingSpheres() + + this.selected = [] + this.obj3d.dispatchEvent({ type: 'change' }) +} + +export async function setTangent() { + let selection = await this.awaitSelection({ line: 2 }) + if (selection == null) return; + + let idx = -1 + for (let i = 0; i < 2; i++) { + if (selection[i].userData.ccw == undefined) { + idx = i + break + } + } + + let arr = idx == 0 ? + [-1, -1, selection[1].name, selection[0].name] : + [-1, -1, selection[0].name, selection[1].name]; + + let type = idx == -1 ? 'curve_curve_tangent' : 'arc_line_tangent' + + this.constraints.set(++this.c_id, + [ + type, -1, + arr + ] + ) + selection.forEach(element => { + element.userData.constraints.push(this.c_id) + }); this.updateOtherBuffers() @@ -59,3 +108,4 @@ export function setOrdinate(dir = 0) { } + diff --git a/src/drawArc.js b/src/drawArc.js index b68df97..d2dc6fc 100644 --- a/src/drawArc.js +++ b/src/drawArc.js @@ -1,6 +1,7 @@ -import {ptObj, lineObj} from './shared' +import { Vector2 } from 'three'; +import { ptObj, lineObj } from './shared' const n = 30 @@ -9,13 +10,14 @@ export function drawArc(mouseLoc) { const p1 = ptObj(mouseLoc) p1.matrixAutoUpdate = false; p1.userData.constraints = [] - + const p2 = ptObj() p2.matrixAutoUpdate = false; p2.userData.constraints = [] const arc = lineObj(n) arc.frustumCulled = false; + arc.userData.constraints = [] const p3 = ptObj() p3.matrixAutoUpdate = false; @@ -44,6 +46,81 @@ export function drawArc2(mouseLoc, toPush) { p3.geometry.computeBoundingSphere() } + + +const mdpt1 = new Vector2() +const mdpt2 = new Vector2() +const bis1 = new Vector2() +const bis2 = new Vector2() +const _vec2 = new Vector2() +const _p1 = new Vector2() +const _p2 = new Vector2() +const _l12 = new Vector2() + + +export function arcOnClick2(p1, p2) { + _p1.set( + p1.geometry.attributes.position.array[0], + p1.geometry.attributes.position.array[1] + ) + _p2.set( + p2.geometry.attributes.position.array[0], + p2.geometry.attributes.position.array[1] + ) + _l12.subVectors(_p2, _p1) + bis1.set(-_l12.y, _l12.x) + mdpt1.addVectors(_p1, _l12.multiplyScalar(0.5)) +} + +let r_cross_s, centerScalar, ccw, points +export function drawArc3(mouseLoc, toPush) { + const [p1, p2, p3, arc] = toPush + + _vec2.set(mouseLoc.x - _p1.x, mouseLoc.y - _p1.y) + + ccw = _l12.cross(_vec2) < 0 ? 1 : 0; + + bis2.set(-_vec2.y, _vec2.x) + mdpt2.addVectors(_p1, _vec2.multiplyScalar(0.5)) + + // https://stackoverflow.com/questions/563198/ + r_cross_s = bis1.cross(bis2); + if (r_cross_s === 0) { + centerScalar = 0.5 + } else { + centerScalar = _vec2.subVectors(mdpt2, mdpt1).cross(bis1) / r_cross_s; + } + + p3.geometry.attributes.position.set( + _vec2.addVectors(mdpt2, bis2.multiplyScalar(centerScalar)).toArray() + ); + + p3.geometry.attributes.position.needsUpdate = true; + p3.geometry.computeBoundingSphere() + + if (ccw) { + points = get3PtArc( + p1.geometry.attributes.position.array, + p2.geometry.attributes.position.array, + p3.geometry.attributes.position.array + ) + } else { + points = get3PtArc( + p2.geometry.attributes.position.array, + p1.geometry.attributes.position.array, + p3.geometry.attributes.position.array + ) + } + + arc.geometry.attributes.position.set( + points + ); + arc.geometry.attributes.position.needsUpdate = true; + arc.userData.ccw = ccw; + + return ccw +} + export function get2PtArc(p1, p2, divisions = n) { const dx = p2[0] - p1[0] @@ -85,7 +162,7 @@ export function get3PtArc(p1, p2, c, divisions = n) { let deltaAngle = a2 - a1 - if (deltaAngle <=0) deltaAngle += Math.PI*2 + if (deltaAngle <= 0) deltaAngle += Math.PI * 2 // let deltaAngle = a2 - a1 // if (deltaAngle > Math.PI ){ @@ -99,7 +176,7 @@ export function get3PtArc(p1, p2, c, divisions = n) { // deltaAngle = Math.PI*2 - deltaAngle // } - + let points = new Float32Array((divisions + 1) * 3) for (let d = 0; d <= divisions; d++) { @@ -115,7 +192,7 @@ export function getAngleArc(a1, a2, c, radius, divisions = n) { let deltaAngle = a2 - a1 - + let points = new Float32Array((divisions + 1) * 3) for (let d = 0; d <= divisions; d++) { diff --git a/src/drawDimension.js b/src/drawDimension.js index 9b5de07..f98722b 100644 --- a/src/drawDimension.js +++ b/src/drawDimension.js @@ -314,7 +314,6 @@ function updateDistance(linegeom, pointgeom, _p1, _p2, offset) { proj1 = dir.clone().multiplyScalar(hyp1.dot(dir)) hyp2 = tagPos.clone().sub(p2) // note that this value is used to calculate tag-p2 offset - console.log(hyp2, 'hereeeeee') proj2 = dir.clone().multiplyScalar(hyp2.dot(dir)) p1eArr = tagPos.clone().sub(proj1).toArray() diff --git a/src/drawEvents.js b/src/drawEvents.js index 1273bd2..924c369 100644 --- a/src/drawEvents.js +++ b/src/drawEvents.js @@ -1,5 +1,5 @@ -import { drawArc, drawArc2 } from './drawArc' +import { drawArc, drawArc2, arcOnClick2, drawArc3 } from './drawArc' import { drawLine, drawLine2 } from './drawLine' import { ptObj } from './shared' @@ -15,10 +15,8 @@ export function drawOnClick1(e) { this.toPush = drawLine.call(this, mouseLoc) } else if (this.mode == "arc") { this.toPush = drawArc(mouseLoc) - } else if (this.mode == 'dim') { - this.curDimension = drawDimension.call(this) } else if (this.mode == 'point') { - this.toPush = drawPoint.call(this, mouseLoc) + this.toPush = drawPoint(mouseLoc) } this.toPush.forEach(element => { @@ -61,28 +59,43 @@ export function drawOnClick2(e) { this.subsequent = true this.drawOnClick1(e) - } else if (this.mode == "arc") { - // this.toPush = [] - // this.canvas.addEventListener('pointermove', this.drawPreClick3) - // this.canvas.addEventListener('pointerdown', this.drawOnClick3) } else if (this.mode == "point") { this.drawOnClick1(e) + } else if (this.mode == "arc") { + + arcOnClick2(this.toPush[0], this.toPush[1]) + + this.canvas.addEventListener('pointermove', this.drawPreClick3) + this.canvas.addEventListener('pointerdown', this.drawOnClick3) } } +let ccw; export function drawPreClick3(e) { - const mouseLoc = this.getLocation(e).toArray(); - + const mouseLoc = this.getLocation(e); + ccw = drawArc3(mouseLoc, this.toPush) sc.render() } - export function drawOnClick3(e) { if (e.buttons !== 1) return; this.canvas.removeEventListener('pointermove', this.drawPreClick3); this.canvas.removeEventListener('pointerdown', this.drawOnClick3); + if (!ccw) { + let temp + const ent = this.linkedObjs.get(this.l_id - 1) + temp = ent[1][0] + ent[1][0] = ent[1][1] + ent[1][1] = temp + this.linkedObjs.set(this.l_id - 1, ent) + let i = (this.linkedObjs.size - 1) * 5 + temp = this.linksBuf[i + 1] + this.linksBuf[i + 1] = this.linksBuf[i + 2] + this.linksBuf[i + 2] = temp + } + this.canvas.addEventListener('pointerdown', this.drawOnClick1) } @@ -97,6 +110,18 @@ export function drawClear() { this.delete(this.obj3d.children[this.updatePoint]) + this.obj3d.dispatchEvent({ type: 'change' }) + this.subsequent = false + this.toPush = [] + } if (this.mode == "arc") { + this.canvas.removeEventListener('pointerdown', this.drawOnClick1) + this.canvas.removeEventListener('pointermove', this.drawPreClick2); + this.canvas.removeEventListener('pointerdown', this.drawOnClick2); + this.canvas.removeEventListener('pointermove', this.drawPreClick3); + this.canvas.removeEventListener('pointerdown', this.drawOnClick3); + + this.delete(this.obj3d.children[this.updatePoint]) + this.obj3d.dispatchEvent({ type: 'change' }) this.subsequent = false this.toPush = [] diff --git a/src/react/icons.jsx b/src/react/icons.jsx index 1ecd465..dfaf4e5 100644 --- a/src/react/icons.jsx +++ b/src/react/icons.jsx @@ -8,17 +8,25 @@ function Arc(props) { viewBox="0 0 16 16" {...props} > - - - - + + + + + ); } @@ -355,10 +363,14 @@ function Line(props) { {...props} > - + @@ -437,6 +449,29 @@ function Subtract(props) { ); } +function Tangent(props) { + return ( + + + + + + + ); +} + function Union(props) { return ( ); } -export { Arc, Coincident, Dimension, Extrude, Extrude_master, Horizontal, Intersect, Intersect_thin, Line, Stl, Subtract, Union, Union_thin, Vertical }; \ No newline at end of file +export { Arc, Coincident, Dimension, Extrude, Extrude_master, Horizontal, Intersect, Intersect_thin, Line, Stl, Subtract, Tangent, Union, Union_thin, Vertical }; \ No newline at end of file diff --git a/src/react/navBar.jsx b/src/react/navBar.jsx index d9236f6..14b0448 100644 --- a/src/react/navBar.jsx +++ b/src/react/navBar.jsx @@ -5,10 +5,10 @@ import React, { useEffect, useReducer } from 'react'; import { useDispatch, useSelector } from 'react-redux' import { FaCube, FaEdit } from 'react-icons/fa' -import { BsBoxArrowUp} from 'react-icons/bs' -import { MdDone, MdSave, MdFolder} from 'react-icons/md' +import { BsBoxArrowUp } from 'react-icons/bs' +import { MdDone, MdSave, MdFolder } from 'react-icons/md' import * as Icon from "./icons"; - +import { setCoincident, setOrdinate, setTangent } from '../constraintEvents' export const NavBar = () => { @@ -55,9 +55,10 @@ export const NavBar = () => { [Icon.Dimension, () => sc.activeSketch.drawDimension(), 'Dimension [d]'], [Icon.Line, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Line [l]'], [Icon.Arc, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc [a]'], - [Icon.Coincident, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc [space]'], - [Icon.Vertical, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc [v]'], - [Icon.Horizontal, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc [h]'], + [Icon.Coincident, () => setCoincident.call(sc.activeSketch), 'Coincident [c]'], + [Icon.Vertical, () => setOrdinate.call(sc.activeSketch, 0), 'Vertical [v]'], + [Icon.Horizontal, () => setOrdinate.call(sc.activeSketch, 1), 'Horizontal [h]'], + [Icon.Tangent, () => setTangent.call(sc.activeSketch), 'Tangent [t]'], ] diff --git a/todo.txt b/todo.txt index 2b9bfb9..bfeca1b 100644 --- a/todo.txt +++ b/todo.txt @@ -41,7 +41,7 @@ better default ent names reattach sketch -3 pt arc +3 pt arc // done auto snap constraint labels,tangent, equal