mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-12 11:25:04 +01:00
improving dimensions - make them draggable
This commit is contained in:
parent
11c37cb8b9
commit
5dc7c3f52b
4 changed files with 144 additions and 158 deletions
|
|
@ -39,6 +39,12 @@ export function distanceSquared3(x1, y1, z1, x2, y2, z2) {
|
|||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
export function distanceSquared(x1, y1, x2, y2) {
|
||||
const dx = x1 - x2;
|
||||
const dy = y1 - y2;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
export function circleFromPoints(p1, p2, p3) {
|
||||
var center = new Vector();
|
||||
var offset = p2.x*p2.x + p2.y*p2.y;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import * as utils from '../../utils/utils'
|
||||
import * as math from '../../math/math'
|
||||
import Vector from 'math/vector';
|
||||
import {SketchObject} from './sketch-object'
|
||||
import {Styles} from "../styles";
|
||||
import {_90} from "../../math/math";
|
||||
import {_270} from "../../math/math";
|
||||
import {makeAngle0_360} from "../../math/math";
|
||||
|
||||
class LinearDimension extends SketchObject {
|
||||
|
||||
|
|
@ -10,6 +13,9 @@ class LinearDimension extends SketchObject {
|
|||
this.a = a;
|
||||
this.b = b;
|
||||
this.flip = false;
|
||||
this.offset = 15;
|
||||
this.pickA = [];
|
||||
this.pickB = [];
|
||||
}
|
||||
|
||||
visitParams(callback) {
|
||||
|
|
@ -20,6 +26,20 @@ class LinearDimension extends SketchObject {
|
|||
}
|
||||
|
||||
translateImpl(dx, dy) {
|
||||
|
||||
const [_ax, _ay] = this.pickA;
|
||||
const [_bx, _by] = this.pickB;
|
||||
|
||||
let _vx = - (_by - _ay);
|
||||
let _vy = _bx - _ax;
|
||||
|
||||
const d = math.distance(_ax, _ay, _bx, _by);
|
||||
|
||||
//normalize
|
||||
let _vxn = _vx / d;
|
||||
let _vyn = _vy / d;
|
||||
|
||||
this.offset += (dx * _vxn + dy * _vyn) * this.unscale;
|
||||
}
|
||||
|
||||
getA() { return this.a }
|
||||
|
|
@ -27,43 +47,45 @@ class LinearDimension extends SketchObject {
|
|||
|
||||
drawImpl(ctx, scale, viewer) {
|
||||
|
||||
const marked = this.markers.length !== 0;
|
||||
|
||||
if (marked) {
|
||||
ctx.save();
|
||||
viewer.setStyle(Styles.HIGHLIGHT, ctx);
|
||||
}
|
||||
|
||||
const dimScale = viewer.dimScale;
|
||||
|
||||
const unscale = 1 /scale;
|
||||
const off = unscale * 15;
|
||||
const off = unscale * this.offset;
|
||||
const textOff = unscale * 3; // getTextOff(dimScale);
|
||||
|
||||
var a, b, startA, startB;
|
||||
if (this.flip) {
|
||||
a = this.getB();
|
||||
b = this.getA();
|
||||
startA = this.b;
|
||||
startB = this.a;
|
||||
} else {
|
||||
a = this.getA();
|
||||
b = this.getB();
|
||||
startA = this.a;
|
||||
startB = this.b;
|
||||
}
|
||||
|
||||
|
||||
this.unscale = scale;
|
||||
|
||||
let a, b, startA, startB;
|
||||
a = this.getB();
|
||||
b = this.getA();
|
||||
startA = this.b;
|
||||
startB = this.a;
|
||||
|
||||
const d = math.distanceAB(a, b);
|
||||
|
||||
var _vx = - (b.y - a.y);
|
||||
var _vy = b.x - a.x;
|
||||
|
||||
let _vx = - (b.y - a.y);
|
||||
let _vy = b.x - a.x;
|
||||
|
||||
//normalize
|
||||
var _vxn = _vx / d;
|
||||
var _vyn = _vy / d;
|
||||
let _vxn = _vx / d;
|
||||
let _vyn = _vy / d;
|
||||
|
||||
_vx = _vxn * off;
|
||||
_vy = _vyn * off;
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
var _ax = a.x + _vx;
|
||||
var _ay = a.y + _vy;
|
||||
var _bx = b.x + _vx;
|
||||
var _by = b.y + _vy;
|
||||
|
||||
let _ax = a.x + _vx;
|
||||
let _ay = a.y + _vy;
|
||||
let _bx = b.x + _vx;
|
||||
let _by = b.y + _vy;
|
||||
|
||||
ctx.moveTo(_ax, _ay);
|
||||
ctx.lineTo(_bx, _by);
|
||||
|
|
@ -98,10 +120,14 @@ class LinearDimension extends SketchObject {
|
|||
ctx.fill();
|
||||
}
|
||||
|
||||
function drawExtensionLine(x, y, nx, ny, width) {
|
||||
function drawExtensionLine(x, y, nx, ny, width, tip) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + ny * arrowW, y + -nx * arrowW);
|
||||
ctx.lineTo(x + ny * (arrowW + width), y + -nx * (arrowW + width));
|
||||
|
||||
tip[0] = x + ny * (arrowW + width);
|
||||
tip[1] = y + -nx * (arrowW + width);
|
||||
|
||||
ctx.lineTo(tip[0], tip[1]);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
|
@ -119,12 +145,20 @@ class LinearDimension extends SketchObject {
|
|||
|
||||
const innerMode = modelTextWidth <= availableArea;
|
||||
|
||||
let rot = makeAngle0_360(Math.atan2(-_vxn, _vyn));
|
||||
const flip = rot > _90 && rot < _270;
|
||||
if (flip) {
|
||||
rot += Math.PI;
|
||||
}
|
||||
let tx, ty;
|
||||
|
||||
if (innerMode) {
|
||||
drawArrow(_ax, _ay, _vxn, _vyn);
|
||||
drawArrow(_bx, _by, -_vxn, -_vyn);
|
||||
|
||||
this.pickA[0] = _ax; this.pickA[1] = _ay;
|
||||
this.pickB[0] = _bx; this.pickB[1] = _by;
|
||||
|
||||
const h = d/2 - modelTextWidth/2;
|
||||
tx = (_ax + _vxn * textOff) - (- _vyn) * h;
|
||||
ty = (_ay + _vyn * textOff) - ( _vxn) * h;
|
||||
|
|
@ -133,24 +167,59 @@ class LinearDimension extends SketchObject {
|
|||
drawArrow(_bx, _by, _vxn, _vyn);
|
||||
const outerArrowToTextPaddingPx = 6;
|
||||
|
||||
drawExtensionLine(_bx, _by, _vxn, _vyn, modelTextWidth + 2 * outerArrowToTextPaddingPx * unscale);
|
||||
drawExtensionLine(_ax, _ay, -_vxn, -_vyn, outerArrowToTextPaddingPx * unscale);
|
||||
|
||||
drawExtensionLine(_ax, _ay, -_vxn, -_vyn, outerArrowToTextPaddingPx * unscale, this.pickA);
|
||||
drawExtensionLine(_bx, _by, _vxn, _vyn, modelTextWidth + 2 * outerArrowToTextPaddingPx * unscale, this.pickB);
|
||||
|
||||
tx = (_bx + _vxn * textOff) - (- _vyn) * (arrowWpx + outerArrowToTextPaddingPx) * unscale;
|
||||
ty = (_by + _vyn * textOff) - ( _vxn) * (arrowWpx + outerArrowToTextPaddingPx) * unscale;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(tx, ty);
|
||||
ctx.rotate( - Math.atan2(_vxn, _vyn));
|
||||
if (flip) {
|
||||
ctx.translate(_vyn * modelTextWidth - _vxn * 2 *textOff, -_vxn * modelTextWidth - _vyn * 2*textOff);
|
||||
}
|
||||
|
||||
ctx.rotate(rot);
|
||||
ctx.scale(unscale, -unscale);
|
||||
ctx.fillText(txt, 0, 0);
|
||||
ctx.restore();
|
||||
|
||||
if (marked) {
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
normalDistance(aim) {
|
||||
return -1;
|
||||
normalDistance(aim, scale) {
|
||||
|
||||
const [_ax, _ay] = this.pickA;
|
||||
const [_bx, _by] = this.pickB;
|
||||
|
||||
let _vx = - (_by - _ay);
|
||||
let _vy = _bx - _ax;
|
||||
|
||||
const d = math.distance(_ax, _ay, _bx, _by);
|
||||
|
||||
//normalize
|
||||
let _vxn = _vx / d;
|
||||
let _vyn = _vy / d;
|
||||
|
||||
let avx = aim.x - _ax;
|
||||
let avy = aim.y - _ay;
|
||||
|
||||
const proj = avx * _vyn + avy * (-_vxn);
|
||||
|
||||
//Check if vector b lays on the vector ab
|
||||
if (proj > d) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (proj < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Math.abs(avx * _vxn + avy * _vyn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,19 +14,19 @@ export class DragTool extends Tool {
|
|||
}
|
||||
|
||||
mousemove(e) {
|
||||
var x = this._point.x;
|
||||
var y = this._point.y;
|
||||
let x = this._point.x;
|
||||
let y = this._point.y;
|
||||
this.viewer.screenToModel2(e.offsetX, e.offsetY, this._point);
|
||||
var dx = this._point.x - x;
|
||||
var dy = this._point.y - y;
|
||||
// for (var i = 0; i < this.lockedShifts.length; i += 2) {
|
||||
let dx = this._point.x - x;
|
||||
let dy = this._point.y - y;
|
||||
// for (let i = 0; i < this.lockedShifts.length; i += 2) {
|
||||
// this.lockedValues[i] = this._point.x - this.lockedShifts[i];
|
||||
// this.lockedValues[i + 1] = this._point.y - this.lockedShifts[i + 1];
|
||||
// }
|
||||
|
||||
this.obj.translate(dx, dy);
|
||||
// this.viewer.parametricManager.setConstantsFromGeometry(this.obj);
|
||||
if (!Tool.dumbMode(e)) {
|
||||
if (!Tool.dumbMode(e) || this.obj.constraints.length !== 0) {
|
||||
// this.viewer.parametricManager.prepare();
|
||||
this.viewer.parametricManager.solve(true);
|
||||
}
|
||||
|
|
@ -40,9 +40,10 @@ export class DragTool extends Tool {
|
|||
this.origin.x = e.offsetX;
|
||||
this.origin.y = e.offsetY;
|
||||
this.viewer.screenToModel2(e.offsetX, e.offsetY, this._point);
|
||||
|
||||
this.viewer.parametricManager.algNumSystem.controlBounds = true;
|
||||
this.viewer.parametricManager.prepare([this.obj]);
|
||||
if (this.obj.constraints.length !== 0) {
|
||||
this.viewer.parametricManager.algNumSystem.controlBounds = true;
|
||||
this.viewer.parametricManager.prepare([this.obj]);
|
||||
}
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
|
|
@ -50,7 +51,7 @@ export class DragTool extends Tool {
|
|||
this.viewer.refresh();
|
||||
this.viewer.parametricManager.algNumSystem.controlBounds = false;
|
||||
this.viewer.toolManager.releaseControl();
|
||||
var traveled = math.distance(this.origin.x, this.origin.y, e.offsetX, e.offsetY);
|
||||
let traveled = math.distance(this.origin.x, this.origin.y, e.offsetX, e.offsetY);
|
||||
if (traveled >= 10) {
|
||||
this.viewer.historyManager.lightCheckpoint(10);
|
||||
}
|
||||
|
|
@ -60,96 +61,4 @@ export class DragTool extends Tool {
|
|||
mousewheel(e) {
|
||||
}
|
||||
|
||||
solveRequest(rough) {
|
||||
var paramsToUpdate = [];
|
||||
this.viewer.accept(function (obj) {
|
||||
if (obj.aux !== true) {
|
||||
if (obj.recoverIfNecessary()){
|
||||
obj.collectParams(paramsToUpdate);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (paramsToUpdate.length != 0) {
|
||||
for (var i = 0; i < paramsToUpdate.length; i++) {
|
||||
this.solver.updateParameter(paramsToUpdate[i]);
|
||||
}
|
||||
this.solver.solve(rough, 1);
|
||||
}
|
||||
}
|
||||
|
||||
getParamsToLock() {
|
||||
var params = [];
|
||||
this.obj.accept(function (obj) {
|
||||
if (obj._class === 'TCAD.TWO.EndPoint' && !obj.fullyConstrained) {
|
||||
params.push(obj._x);
|
||||
params.push(obj._y);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return params;
|
||||
}
|
||||
|
||||
prepareSolver(extraConstraints) {
|
||||
var locked = this.getParamsToLock();
|
||||
this.lockedShifts = [];
|
||||
this.lockedValues = [];
|
||||
for (var i = 0; i < locked.length; i += 2) {
|
||||
this.lockedShifts[i] = this._point.x - locked[i].get();
|
||||
this.lockedShifts[i + 1] = this._point.y - locked[i + 1].get();
|
||||
}
|
||||
this.solver = this.viewer.parametricManager.prepare(locked, extraConstraints);
|
||||
//this.enableRecording();
|
||||
}
|
||||
|
||||
enableRecording() {
|
||||
var solver = this.solver;
|
||||
DragTool.snapshots = [];
|
||||
optim.DEBUG_HANDLER = () => {
|
||||
DragTool.snapshots.push([]);
|
||||
for (var i = 0; i < solver.solvers.length; i++) {
|
||||
var sys = solver.solvers[i].system;
|
||||
DragTool.snapshots[i].push(sys.params.map(function (p) {
|
||||
return p.get()
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
animateSolution() {
|
||||
if (DragTool.snapshots.length === 0) return;
|
||||
var stepNum = 0;
|
||||
var scope = this;
|
||||
var then = Date.now();
|
||||
var speed = 500;
|
||||
|
||||
function step() {
|
||||
var now = Date.now();
|
||||
var elapsed = now - then;
|
||||
|
||||
if (elapsed > speed) {
|
||||
for (var i = 0; i < scope.solver.solvers.length; i++) {
|
||||
var sys = scope.solver.solvers[i].system;
|
||||
if (stepNum >= DragTool.snapshots[i].length) continue;
|
||||
var values = DragTool.snapshots[i][stepNum];
|
||||
for (var k = 0; k < values.length; k++) {
|
||||
sys.params[k]._backingParam.set(values[k]);
|
||||
}
|
||||
}
|
||||
stepNum++;
|
||||
|
||||
then = now;
|
||||
scope.viewer.repaint();
|
||||
}
|
||||
|
||||
if (DragTool.snapshots.length != 0 && stepNum < DragTool.snapshots[0].length) {
|
||||
window.requestAnimationFrame(step);
|
||||
}
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(step);
|
||||
}
|
||||
}
|
||||
|
||||
DragTool.snapshots = [];
|
||||
|
|
|
|||
|
|
@ -163,29 +163,31 @@ class Viewer {
|
|||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.layers.length; i++) {
|
||||
var objs = this.layers[i].objects;
|
||||
for (var j = 0; j < objs.length; j++) {
|
||||
var l = unreachable + 1;
|
||||
var before = pickResult.length;
|
||||
objs[j].accept((o) => {
|
||||
if (!o.visible) return true;
|
||||
if (onlyPoints && !isEndPoint(o)) {
|
||||
for (let layers of this._workspace) {
|
||||
for (let i = 0; i < layers.length; i++) {
|
||||
var objs = layers[i].objects;
|
||||
for (var j = 0; j < objs.length; j++) {
|
||||
var l = unreachable + 1;
|
||||
var before = pickResult.length;
|
||||
objs[j].accept((o) => {
|
||||
if (!o.visible) return true;
|
||||
if (onlyPoints && !isEndPoint(o)) {
|
||||
return true;
|
||||
}
|
||||
l = o.normalDistance(aim, this.scale / this.retinaPxielRatio);
|
||||
if (l >= 0 && l <= buffer && !isFiltered(o)) {
|
||||
pickResult.push(o);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
l = o.normalDistance(aim, this.scale);
|
||||
if (l >= 0 && l <= buffer && !isFiltered(o)) {
|
||||
pickResult.push(o);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
var hit = before - pickResult.length != 0;
|
||||
if (hit) {
|
||||
if (!deep && pickResult.length != 0) return pickResult;
|
||||
if (l >= 0 && l < heroLength) {
|
||||
heroLength = l;
|
||||
heroIdx = pickResult.length - 1;
|
||||
});
|
||||
var hit = before - pickResult.length != 0;
|
||||
if (hit) {
|
||||
if (!deep && pickResult.length != 0) return pickResult;
|
||||
if (l >= 0 && l < heroLength) {
|
||||
heroLength = l;
|
||||
heroIdx = pickResult.length - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue