mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-07 17:04:58 +01:00
Offset curve for 2d sketcher. #32
This commit is contained in:
parent
738505be2b
commit
cbfdbae209
6 changed files with 191 additions and 3 deletions
|
|
@ -98,12 +98,12 @@ export function rotateInPlace(px, py, angle, out) {
|
|||
return out;
|
||||
}
|
||||
|
||||
export function polygonOffset( polygon, scale ) {
|
||||
export function polygonOffsetXY(polygon, scaleX, scaleY) {
|
||||
const origBBox = new BBox();
|
||||
const scaledBBox = new BBox();
|
||||
const result = [];
|
||||
for (let point of polygon) {
|
||||
const scaledPoint = new Vector(point.x, point.y)._multiply(scale);
|
||||
const scaledPoint = new Vector(point.x * scaleX, point.y * scaleY);
|
||||
result.push(scaledPoint);
|
||||
origBBox.checkPoint(point);
|
||||
scaledBBox.checkPoint(scaledPoint);
|
||||
|
|
@ -115,6 +115,21 @@ export function polygonOffset( polygon, scale ) {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
export function polygonOffset( polygon, scale ) {
|
||||
return polygonOffsetXY( polygon, scale, scale );
|
||||
}
|
||||
|
||||
export function polygonOffsetByDelta( polygon, delta ) {
|
||||
const origBBox = new BBox();
|
||||
for (let point of polygon) {
|
||||
origBBox.checkPoint(point);
|
||||
}
|
||||
const width = origBBox.width();
|
||||
const height = origBBox.height();
|
||||
return polygonOffsetXY(polygon, (width + delta) / width, (height + delta) / height);
|
||||
}
|
||||
|
||||
export function isPointInsidePolygon( inPt, inPolygon ) {
|
||||
var EPSILON = TOLERANCE;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {EllipticalArc} from './shapes/elliptical-arc'
|
|||
import {BezierCurve} from './shapes/bezier-curve'
|
||||
import {HDimension, VDimension, Dimension, DiameterDimension} from './shapes/dim'
|
||||
import {Constraints} from './parametric'
|
||||
import {HashTable} from '../utils/hashmap'
|
||||
import Vector from '../math/vector'
|
||||
|
||||
const Types = {
|
||||
|
|
@ -192,6 +193,10 @@ IO.prototype._loadSketch = function(sketch) {
|
|||
if (boundaryNeedsUpdate) {
|
||||
this.addNewBoundaryObjects(boundary, maxEdge);
|
||||
}
|
||||
const boundaryLayer = this.viewer.findLayerByName(IO.BOUNDARY_LAYER_NAME);
|
||||
if (boundaryLayer != null) {
|
||||
this.linkEndPoints(boundaryLayer.objects);
|
||||
}
|
||||
|
||||
var sketchConstraints = sketch['constraints'];
|
||||
if (sketchConstraints !== undefined) {
|
||||
|
|
@ -211,6 +216,24 @@ IO.prototype._loadSketch = function(sketch) {
|
|||
}
|
||||
};
|
||||
|
||||
IO.prototype.linkEndPoints = function(objects) {
|
||||
const index = HashTable.forVector2d();
|
||||
for (let obj of objects) {
|
||||
obj.accept((o) => {
|
||||
if (o._class == Types.END_POINT) {
|
||||
const equalPoint = index.get(o);
|
||||
if (equalPoint == null) {
|
||||
index.put(o, o);
|
||||
} else {
|
||||
o.linked.push(equalPoint);
|
||||
equalPoint.linked.push(o);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
IO.prototype.synchLine = function(skobj, edgeObj) {
|
||||
skobj.a.x = edgeObj.a.x;
|
||||
skobj.a.y = edgeObj.a.y;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {FilletTool} from './tools/fillet'
|
|||
import {EllipseTool} from './tools/ellipse'
|
||||
import {BezierCurveTool} from './tools/bezier-curve'
|
||||
import {RectangleTool} from './tools/rectangle'
|
||||
import {OffsetTool} from './tools/offset'
|
||||
import {ReferencePointTool} from './tools/origin'
|
||||
import {InputManager} from './input-manager'
|
||||
|
||||
|
|
@ -153,6 +154,10 @@ function App2D() {
|
|||
app.viewer.toolManager.takeControl(new RectangleTool(app.viewer));
|
||||
}, 'rect');
|
||||
|
||||
this.registerAction('offsetTool', "Polygon Offset", function () {
|
||||
app.viewer.toolManager.takeControl(new OffsetTool(app.viewer));
|
||||
});
|
||||
|
||||
this.registerAction('pan', "Pan", function () {
|
||||
app.viewer.toolManager.releaseControl();
|
||||
});
|
||||
|
|
|
|||
117
web/app/sketcher/tools/loop-pick.js
Normal file
117
web/app/sketcher/tools/loop-pick.js
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
import {Tool} from './tool'
|
||||
import {Graph} from '../../math/graph'
|
||||
import {Styles} from '../styles'
|
||||
|
||||
export class LoopPickTool extends Tool {
|
||||
|
||||
constructor(name, viewer) {
|
||||
super(name, viewer);
|
||||
this.loops = new Map();
|
||||
this.marked = new Set();
|
||||
this.pickedLoop = null;
|
||||
}
|
||||
|
||||
restart() {
|
||||
this.sendHint('pick a polygon');
|
||||
this.reindexLoops();
|
||||
this.marked.clear();
|
||||
this.pickedLoop = null;
|
||||
};
|
||||
|
||||
cleanup() {
|
||||
this.clearMarked();
|
||||
}
|
||||
|
||||
clearMarked() {
|
||||
for (let obj of this.marked) {
|
||||
obj.marked = null;
|
||||
}
|
||||
this.marked.clear();
|
||||
}
|
||||
|
||||
mark(obj) {
|
||||
if (!this.marked.has(obj)) {
|
||||
obj.marked = Styles.SNAP;
|
||||
this.marked.add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
otherEnd(point) {
|
||||
if (point.parent.a.id == point.id) {
|
||||
return point.parent.b;
|
||||
} else {
|
||||
return point.parent.a;
|
||||
}
|
||||
}
|
||||
|
||||
reindexLoops() {
|
||||
this.loops.clear();
|
||||
const points = [];
|
||||
this.viewer.accept((obj) => {
|
||||
if (obj._class == 'TCAD.TWO.EndPoint' && obj.parent && obj.parent.a && obj.parent.b) {
|
||||
points.push(obj);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
const graph = {
|
||||
|
||||
connections : (p) => {
|
||||
const conns = [this.otherEnd(p)];
|
||||
p.linked.forEach(l => conns.push(this.otherEnd(l)));
|
||||
return conns;
|
||||
},
|
||||
|
||||
at : function(index) {
|
||||
return points[index];
|
||||
},
|
||||
|
||||
size : function() {
|
||||
return points.length;
|
||||
}
|
||||
};
|
||||
const loops = Graph.findAllLoops(graph, (p) => p.id, (a, b) => a.id == b.id);
|
||||
for (let loop of loops) {
|
||||
for (let point of loop) {
|
||||
this.loops.set(point, loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.clearMarked();
|
||||
this.pickedLoop = null;
|
||||
const p = this.viewer.screenToModel(e);
|
||||
this.pickedLoop = this.pickLoop(p);
|
||||
if (this.pickedLoop != null) {
|
||||
for (let p of this.pickedLoop) {
|
||||
this.mark(p.parent);
|
||||
}
|
||||
}
|
||||
this.viewer.refresh();
|
||||
};
|
||||
|
||||
pickLoop(p) {
|
||||
const pickResult = this.viewer.search(p.x, p.y, 20 / this.viewer.scale, true, false, []);
|
||||
for (let obj of pickResult) {
|
||||
for (let point of [obj.a, obj.b]) {
|
||||
const loop = this.loops.get(point);
|
||||
if (loop) {
|
||||
return loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
if (this.pickedLoop == null) {
|
||||
this.viewer.toolManager.releaseControl();
|
||||
this.viewer.toolManager.tool.mousedown(e);
|
||||
} else {
|
||||
this.onMousedown(e);
|
||||
}
|
||||
};
|
||||
|
||||
onMousedown(e) {};
|
||||
|
||||
}
|
||||
27
web/app/sketcher/tools/offset.js
Normal file
27
web/app/sketcher/tools/offset.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import {LoopPickTool} from './loop-pick'
|
||||
import * as math from '../../math/math';
|
||||
|
||||
export class OffsetTool extends LoopPickTool {
|
||||
|
||||
constructor(viewer) {
|
||||
super('offset', viewer);
|
||||
}
|
||||
|
||||
onMousedown(e) {
|
||||
const delta = prompt('offset distance?');
|
||||
const offsetPolygon = math.polygonOffsetByDelta(this.pickedLoop, parseInt(delta));
|
||||
const length = offsetPolygon.length;
|
||||
const segments = [];
|
||||
for (let p = length - 1, q = 0; q < length; p = q++) {
|
||||
const a = offsetPolygon[p];
|
||||
const b = offsetPolygon[q];
|
||||
const segment = this.viewer.addSegment(a.x, a.y, b.x, b.y, this.viewer.activeLayer);
|
||||
segments.push(segment);
|
||||
}
|
||||
for (var i = 0; i < segments.length; i++) {
|
||||
this.viewer.parametricManager.linkObjects([segments[i].b, segments[(i + 1) % segments.length].a]);
|
||||
}
|
||||
this.viewer.toolManager.releaseControl();
|
||||
this.viewer.refresh();
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,8 @@
|
|||
--><button class="btn tbtn act-addEllipse" type="submit" value="">E</button><!--
|
||||
--><button class="btn tbtn act-addEllipticalArc" type="submit" value="">EA</button><!--
|
||||
--><button class="btn tbtn act-addBezierCurve sep" type="submit" value="">BZ</button><!--
|
||||
--><button class="btn tbtn act-addRectangle sep" type="submit" value="">R</button><!--
|
||||
--><button class="btn tbtn act-addRectangle" type="submit" value="">R</button><!--
|
||||
--><button class="btn tbtn act-offsetTool sep" type="submit" value="">F</button><!--
|
||||
--><button class="btn tbtn act-addHDim" style="background-image: url(img/hdim.png);" type="submit" value=""></button><!--
|
||||
--><button class="btn tbtn act-addVDim" style="background-image: url(img/vdim.png);" type="submit" value=""></button><!--
|
||||
--><button class="btn tbtn act-addDim" style="background-image: url(img/dim.png);" type="submit" value=""></button><!--
|
||||
|
|
|
|||
Loading…
Reference in a new issue