From 9e6fdcd03418e60aaaa661089ef9aa9ee7254811 Mon Sep 17 00:00:00 2001 From: howard Date: Thu, 8 Apr 2021 16:05:52 -0700 Subject: [PATCH] implement line pt dim --- src/Scene.js | 11 +-- src/Sketch.js | 12 +-- src/constraintEvents.js | 36 ++++---- src/drawDimension.js | 193 ++++++++++++++++++++++++++++++---------- src/drawEvents.js | 16 ++-- src/react/navBar.jsx | 14 +-- src/react/toolTip.jsx | 1 + src/shared.js | 15 ++-- todo.txt | 5 +- 9 files changed, 205 insertions(+), 98 deletions(-) diff --git a/src/Scene.js b/src/Scene.js index d20a48e..a45d77a 100644 --- a/src/Scene.js +++ b/src/Scene.js @@ -9,7 +9,7 @@ import Stats from './stats.module.js'; import { add3DPoint } from './datums' import { extrude } from './extrude' import { onHover, onPick } from './mouseEvents'; -import { _vec2, _vec3, color, awaitPts } from './shared' +import { _vec2, _vec3, color, awaitSelection } from './shared' import {AxesHelper} from './axes' @@ -17,6 +17,7 @@ import {AxesHelper} from './axes' import CSG from "./three-csg.js" window.BoolOp = CSG +window.th = THREE const eq = (a1, a2) => { if (a1.length != a2.length) return false @@ -126,7 +127,7 @@ export class Scene { this.extrude = extrude.bind(this); this.onHover = onHover.bind(this); this.onPick = onPick.bind(this); - this.awaitPts = awaitPts.bind(this); + this.awaitSelection = awaitSelection.bind(this); this.obj3d.addEventListener('change', this.render); controls.addEventListener('change', this.render); @@ -239,8 +240,8 @@ function render() { ...ele.geometry.attributes.position.array ).applyMatrix4(matrix).project(this.camera) - x = (pos.x * .5 + .5) * this.canvas.clientWidth + 10; - y = (pos.y * -.5 + .5) * this.canvas.clientHeight; + x = (pos.x * .5 + .5) * this.canvas.clientWidth + 10 + this.rect.left; + y = (pos.y * -.5 + .5) * this.canvas.clientHeight + this.rect.top; ele.label.style.transform = `translate(0%, -50%) translate(${x}px,${y}px)`; } @@ -264,7 +265,7 @@ async function addSketch() { let sketch; - const references = await this.awaitPts({ point: 3 }, { plane: 1 }); + const references = await this.awaitSelection({ point: 3 }, { plane: 1 }); if (!references) return; diff --git a/src/Sketch.js b/src/Sketch.js index 86f7978..94ddbbd 100644 --- a/src/Sketch.js +++ b/src/Sketch.js @@ -2,7 +2,7 @@ import * as THREE from '../node_modules/three/src/Three'; -import { _vec2, _vec3, raycaster, awaitPts, ptObj } from './shared' +import { _vec2, _vec3, raycaster, awaitSelection, ptObj } from './shared' import { drawOnClick1, drawOnClick2, drawPreClick2, drawClear, drawPoint } from './drawEvents' import { onHover, onDrag, onPick, onRelease } from './mouseEvents' @@ -132,7 +132,7 @@ class Sketch { this.setDimLines = setDimLines.bind(this) this.updateDim = updateDim.bind(this) - this.awaitPts = awaitPts.bind(this); + this.awaitSelection = awaitSelection.bind(this); this.onHover = onHover.bind(this); this.onPick = onPick.bind(this); @@ -216,12 +216,8 @@ class Sketch { this.mode = "" break; case 'p': - this.canvas.addEventListener('pointerdown', - (e) => { - drawPoint.call(this, e) - } - ) - + this.canvas.addEventListener('pointerdown', this.drawOnClick1) + this.mode = "point" break; case 'x': this.deleteSelected() diff --git a/src/constraintEvents.js b/src/constraintEvents.js index bf0c5fc..ccf2a47 100644 --- a/src/constraintEvents.js +++ b/src/constraintEvents.js @@ -1,27 +1,33 @@ -export function setCoincident() { - const s = new Set() - const toComb = [] - for (let node of this.selected) { - const xc = node.geometry.attributes.position.array[0] - if (!s.has(xc)) { - toComb.push(node) - s.add(xc) - } - } +export async function setCoincident() { + let selection = await this.awaitSelection({ point: 2 }, { point: 1, line: 1 }) - for (let i = 1; i < toComb.length; i++) { + if (selection == null) return; + + if (selection.every(e => e.userData.type == 'point')) { this.constraints.set(++this.c_id, [ 'points_coincident', -1, - [toComb[i - 1].name, toComb[i].name, -1, -1] /////// + [selection[0].name, selection[1].name, -1, -1] /////// + ] + ) + } else { + + const idx = selection[0].userData.type == 'point' ? [0, 1] : [1, 0] + + this.constraints.set(++this.c_id, + [ + 'pt_on_line', -1, + [selection[idx[0]].name, -1, selection[idx[1]].name, -1] /////// ] ) - toComb[i].userData.constraints.push(this.c_id) - toComb[i - 1].userData.constraints.push(this.c_id) } + selection[1].userData.constraints.push(this.c_id) + selection[0].userData.constraints.push(this.c_id) + + this.updateOtherBuffers() this.solve() this.updateBoundingSpheres() @@ -47,7 +53,7 @@ export function setOrdinate(dir = 0) { ] ) line.userData.constraints.push(this.c_id) - + this.updateOtherBuffers() this.solve() diff --git a/src/drawDimension.js b/src/drawDimension.js index 2258bb5..b8192b5 100644 --- a/src/drawDimension.js +++ b/src/drawDimension.js @@ -4,6 +4,8 @@ import { color } from './shared' const lineMaterial = new THREE.LineBasicMaterial({ linewidth: 2, color: color.dimension, + opacity: 0.2, + transparent: true, }) @@ -14,9 +16,13 @@ const pointMaterial = new THREE.PointsMaterial({ export async function drawDimension() { - let pts = await this.awaitPts({ point: 2 }) + let selection = await this.awaitSelection({ point: 2 }, { point: 1, line: 1 }) + + if (selection == null) return; + + + - if (pts == null) return; const line = new THREE.LineSegments( new THREE.BufferGeometry().setAttribute('position', @@ -32,22 +38,44 @@ export async function drawDimension() { pointMaterial.clone() ) - line.userData.ids = pts.map(e => e.name) + line.userData.ids = selection.map(e => e.name) + + let dist = 0 - for (let i = 0; i < 3; i++) { - dist += (pts[0].geometry.attributes.position.array[i] - pts[1].geometry.attributes.position.array[i]) ** 2 + let ptLineOrder; + + if (selection.every(e => e.userData.type == 'point')) { + for (let i = 0; i < 3; i++) { + dist += (selection[0].geometry.attributes.position.array[i] - selection[1].geometry.attributes.position.array[i]) ** 2 + } + dist = Math.sqrt(dist) + } else { + ptLineOrder = selection[0].userData.type == 'point' ? [0, 1] : [1, 0] + + const lineArr = selection[ptLineOrder[1]].geometry.attributes.position.array + const ptArr = selection[ptLineOrder[0]].geometry.attributes.position.array + + p1.set(lineArr[0], lineArr[1]) + p2.set(lineArr[3], lineArr[4]) + p3.set(ptArr[0], ptArr[1]) + dir = p2.clone().sub(p1).normalize() + hyp = p3.clone().sub(p1) + proj = dir.multiplyScalar(hyp.dot(dir)) + perp = hyp.clone().sub(proj) + + dist = Math.sqrt(perp.x ** 2 + perp.y ** 2) + } - dist = Math.sqrt(dist) + this.obj3d.children[1].add(line).add(point) const onMove = this._onMoveDimension(point, line) - point.label = document.createElement('div'); point.label.textContent = dist.toFixed(3); point.label.contentEditable = true; @@ -70,15 +98,26 @@ export async function drawDimension() { window.removeEventListener('keydown', onKey) point.geometry.computeBoundingSphere() line.geometry.computeBoundingSphere() + if (add) { - this.constraints.set(++this.c_id, //??? - [ - 'pt_pt_distance', dist, - [pts[0].name, pts[1].name, -1, -1] - ] - ) - pts[0].userData.constraints.push(this.c_id) - pts[1].userData.constraints.push(this.c_id) + if (ptLineOrder) { + this.constraints.set(++this.c_id, //??? + [ + 'pt_line_distance', dist, + [selection[ptLineOrder[0]].name, -1, selection[ptLineOrder[1]].name, -1] + ] + ) + } else { + this.constraints.set(++this.c_id, //??? + [ + 'pt_pt_distance', dist, + [selection[0].name, selection[1].name, -1, -1] + ] + ) + } + + selection[0].userData.constraints.push(this.c_id) + selection[1].userData.constraints.push(this.c_id) this.updateOtherBuffers() @@ -109,11 +148,12 @@ export async function drawDimension() { } const p1 = new THREE.Vector2() +const p1x = new THREE.Vector2() const p2 = new THREE.Vector2() const p3 = new THREE.Vector2() -let dir, hyp, proj, perp, p1e, p2e, ids, _p1, _p2; - - +let dir, hyp, proj, perp, p1e, p1eArr, p2e, p2eArr, ids, _p1, _p2, p3Arr +let mdpt, proj1, proj2, hyp1, hyp2 +let dp1e, dp2e, dp12 export function updateDim(c_id) { return (ev_focus) => { @@ -136,7 +176,7 @@ export function updateDim(c_id) { } }) } -} +} @@ -147,9 +187,6 @@ export function _onMoveDimension(point, line) { _p1 = this.obj3d.children[this.objIdx.get(ids[0])].geometry.attributes.position.array _p2 = this.obj3d.children[this.objIdx.get(ids[1])].geometry.attributes.position.array - p1.set(_p1[0], _p1[1]) - p2.set(_p2[0], _p2[1]) - let loc; return (e) => { @@ -159,7 +196,8 @@ export function _onMoveDimension(point, line) { update( line.geometry.attributes.position, - point.geometry.attributes.position + point.geometry.attributes.position, + _p1, _p2 ) point.userData.offset = hyp.toArray() @@ -177,8 +215,6 @@ export function setDimLines() { let point, dist; for (let i = 0; i < dims.length; i += 2) { - - if (restoreLabels) { point = dims[i + 1] // point node is at i+1 dist = this.constraints.get(point.name)[1] @@ -186,56 +222,119 @@ export function setDimLines() { point.label.textContent = dist.toFixed(3); point.label.contentEditable = true; this.labelContainer.append(point.label) - + point.label.addEventListener('focus', this.updateDim(this.c_id)) } - ids = dims[i].userData.ids _p1 = this.obj3d.children[this.objIdx.get(ids[0])].geometry.attributes.position.array _p2 = this.obj3d.children[this.objIdx.get(ids[1])].geometry.attributes.position.array - const offset = dims[i + 1].userData.offset - p1.set(_p1[0], _p1[1]) - p2.set(_p2[0], _p2[1]) + const offset = dims[i + 1].userData.offset p3.set(_p1[0] + offset[0], _p1[1] + offset[1]) + update( dims[i].geometry.attributes.position, - dims[i + 1].geometry.attributes.position + dims[i + 1].geometry.attributes.position, + _p1, + _p2 ) } } -function update(linegeom, pointgeom) { - dir = p2.clone().sub(p1).normalize() - hyp = p3.clone().sub(p1) - proj = dir.multiplyScalar(hyp.dot(dir)) - perp = hyp.clone().sub(proj) +function update(linegeom, pointgeom, _p1, _p2) { - p1e = p1.clone().add(perp).toArray() - p2e = p2.clone().add(perp).toArray() + if (_p1.length == _p2.length) { + p1.set(_p1[0], _p1[1]) + p2.set(_p2[0], _p2[1]) - linegeom.array.set(p1.toArray(), 0) - linegeom.array.set(p1e, 3) + dir = p2.clone().sub(p1).normalize() + hyp = p3.clone().sub(p1) + proj = dir.multiplyScalar(hyp.dot(dir)) + perp = hyp.clone().sub(proj) - linegeom.array.set(p1e, 6) - linegeom.array.set(p2e, 9) + p1e = p1.clone().add(perp) + p1eArr = p1e.toArray() + p2e = p2.clone().add(perp) + p2eArr = p2e.toArray() + p3Arr = p3.toArray() - linegeom.array.set(p2e, 12) + dp1e = p1e.distanceToSquared(p3) + dp2e = p2e.distanceToSquared(p3) + dp12 = p1e.distanceToSquared(p2e) + + linegeom.array.set(p1.toArray(), 0) + + + } else { + if (_p1.length < _p2.length) { + p1.set(_p2[0], _p2[1]) + p1x.set(_p2[3], _p2[4]) + p2.set(_p1[0], _p1[1]) + } else { + p1.set(_p1[0], _p1[1]) + p1x.set(_p1[3], _p1[4]) + p2.set(_p2[0], _p2[1]) + } + + dir = p1x.clone().sub(p1) + mdpt = p1.clone().addScaledVector(dir, 0.5) + dir.normalize() + + hyp = p2.clone().sub(mdpt) + proj = dir.multiplyScalar(hyp.dot(dir)) + + perp = hyp.clone().sub(proj) + dp12 = perp.lengthSq() + + perp.normalize() + + + hyp1 = p3.clone().sub(mdpt) + proj1 = perp.clone().multiplyScalar(hyp1.dot(perp)) + + hyp2 = p3.clone().sub(p2) + proj2 = perp.clone().multiplyScalar(hyp2.dot(perp)) + + + p1eArr = p3.clone().sub(proj1).toArray() + p2eArr = p3.clone().sub(proj2).toArray() + p3Arr = p3.toArray() + + dp1e = proj1.lengthSq() + dp2e = proj2.lengthSq() + + linegeom.array.set(mdpt.toArray(), 0) + + } + + linegeom.array.set(p1eArr, 3) + linegeom.array.set(p1eArr, 6) + linegeom.array.set(p2eArr, 9) + linegeom.array.set(p2eArr, 12) linegeom.array.set(p2.toArray(), 15) - - linegeom.array.set(p1e, 18) - linegeom.array.set(p3.toArray(), 21) + if (dp12 >= dp1e && dp12 >= dp2e) { + linegeom.array.set(p3Arr, 18) + } else { + if (dp1e > dp2e) { + linegeom.array.set(p2eArr, 18) + } else { + linegeom.array.set(p1eArr, 18) + } + } + linegeom.array.set(p3Arr, 21) linegeom.needsUpdate = true; - pointgeom.array.set(p3.toArray()) + pointgeom.array.set(p3Arr) pointgeom.needsUpdate = true; + + } diff --git a/src/drawEvents.js b/src/drawEvents.js index 765a701..86e3830 100644 --- a/src/drawEvents.js +++ b/src/drawEvents.js @@ -1,7 +1,6 @@ import { drawArc, drawArc2 } from './drawArc' import { drawLine, drawLine2 } from './drawLine' -// import { drawDimension } from "./drawDimension"; import { ptObj } from './shared' export function drawOnClick1(e) { @@ -18,6 +17,8 @@ export function drawOnClick1(e) { 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.updatePoint = this.obj3d.children.length @@ -53,14 +54,15 @@ export function drawOnClick2(e) { this.updateOtherBuffers() if (this.mode == "line") { - this.subsequent = true this.drawOnClick1(e) } else if (this.mode == "arc") { - this.toPush = [] + // this.toPush = [] // this.canvas.addEventListener('pointermove', this.drawPreClick3) // this.canvas.addEventListener('pointerdown', this.drawOnClick3) + } else if (this.mode == "point") { + this.drawOnClick1(e) } } @@ -98,14 +100,10 @@ export function drawClear() { } -export function drawPoint(e) { - - const mouseLoc = this.getLocation(e).toArray(); +export function drawPoint(mouseLoc) { const p1 = ptObj() p1.matrixAutoUpdate = false; p1.userData.constraints = [] p1.geometry.attributes.position.set(mouseLoc) - this.obj3d.add(p1) - this.updatePointsBuffer() - this.obj3d.dispatchEvent({ type: 'change' }) + return [p1] } \ No newline at end of file diff --git a/src/react/navBar.jsx b/src/react/navBar.jsx index dd34fdf..1818e80 100644 --- a/src/react/navBar.jsx +++ b/src/react/navBar.jsx @@ -35,9 +35,9 @@ export const NavBar = () => { sc.activeSketch = null // sc.activeDim = this.activeSketch.obj3d.children[1].children }, 'Finish'] : - [FaEdit, sc.addSketch, 'Sketch'] + [FaEdit, sc.addSketch, 'Sketch [s]'] , - [FaCube, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Extrude'], + [FaCube, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Extrude [e]'], [Icon.Union, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Union'], [Icon.Subtract, () => { if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return @@ -51,17 +51,17 @@ export const NavBar = () => { 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'], + [Icon.Dimension, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Dimension [d]'], + [Icon.Line, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Line [l]'], + [Icon.Arc, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc [a]'], ] const [_, forceUpdate] = useReducer(x => x + 1, 0); return
{ - btnz.map(([Icon, fcn, txt], idx) => ( - ( + )) diff --git a/src/react/toolTip.jsx b/src/react/toolTip.jsx index 5620d8f..96324d8 100644 --- a/src/react/toolTip.jsx +++ b/src/react/toolTip.jsx @@ -68,6 +68,7 @@ export const ToolTip = () => { function getTextWidth(text, font = "16px sans-serif") { + console.log(text) // https://stackoverflow.com/a/21015393 // re-use canvas object for better performance let canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas")); diff --git a/src/shared.js b/src/shared.js index f1b542b..eccef33 100644 --- a/src/shared.js +++ b/src/shared.js @@ -13,6 +13,7 @@ raycaster.params.Points.threshold = 0.1; const color = { background:0xdae1e7, + // background:0xbbbbbb, lighting: 0xFFFFFF, emissive: 0x072534, @@ -20,10 +21,12 @@ const color = { point: 0x555555, //points line: 0x555555, //lines mesh: 0x156289, //mesh: - dimension: 0x891d15, // + dimension: 0x0000ff, // - plane: 0xdaacac, // - planeBorder: 0xc59797, // + // plane: 0xdaacac, // + // planeBorder: 0xc59797, // + plane: 0x88adcd, // + planeBorder: 0xa7cae8, // } const hoverColor = { @@ -32,7 +35,7 @@ const hoverColor = { line: 0x00ff00, //lines mesh: 0x00ff00, //mesh: dimension: 0x00ff00, // - plane: 0xff0000, // + plane: 0x005dff, // } @@ -73,7 +76,7 @@ const lineObj = (n = 1) => { } -async function awaitPts(...criteria) { +async function awaitSelection(...criteria) { function fullfilled() { for (let i = criteria.length - 1; i >= 0; i--) { @@ -143,4 +146,4 @@ async function awaitPts(...criteria) { -export { lineMaterial, pointMaterial, _vec2, _vec3, raycaster, color, hoverColor, ptObj, lineObj, awaitPts } \ No newline at end of file +export { lineMaterial, pointMaterial, _vec2, _vec3, raycaster, color, hoverColor, ptObj, lineObj, awaitSelection } \ No newline at end of file diff --git a/todo.txt b/todo.txt index 3094f23..cd18839 100644 --- a/todo.txt +++ b/todo.txt @@ -30,7 +30,10 @@ other constraints / sprite - +tangent +vertical +horizontal +angle