Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0289c5d

Browse filesBrowse files
committed
Merge pull request #65 from Microsoft/dev
Major accuracy upgrade for Combine operations
2 parents 02f8306 + 61f0101 commit 0289c5d
Copy full SHA for 0289c5d
Expand file treeCollapse file tree

20 files changed

+1432
-422
lines changed

‎debug/viewer.css

Copy file name to clipboardExpand all lines: debug/viewer.css
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,8 @@ svg text {
9292
.selectModelCode * {
9393
font-size: 18px;
9494
font-weight: 200;
95+
}
96+
97+
#crosshairs-horizontal_text, #crosshairs-vertical_text {
98+
display: none;
9599
}

‎debug/viewer.html

Copy file name to clipboardExpand all lines: debug/viewer.html
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
<script src="../src/models/OvalArc.js"></script>
4343
<script src="../src/models/ConnectTheDots.js"></script>
4444
<script src="../src/models/Rectangle.js"></script>
45+
<script src="../src/models/Ring.js"></script>
4546
<script src="../src/models/Polygon.js"></script>
4647
<script src="../src/models/Square.js"></script>
4748
<script src="../src/models/SCurve.js"></script>

‎index.js

Copy file name to clipboardExpand all lines: index.js
+322-102Lines changed: 322 additions & 102 deletions
Large diffs are not rendered by default.

‎package.json

Copy file name to clipboardExpand all lines: package.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "makerjs",
3-
"version": "0.5.3",
3+
"version": "0.6.0",
44
"description": "Maker.js, a Microsoft Garage project, is a JavaScript library for creating and sharing modular line drawings for CNC and laser cutters.",
55
"main": "index.js",
66
"scripts": {

‎src/core/angle.ts

Copy file name to clipboardExpand all lines: src/core/angle.ts
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ module MakerJs.angle {
99
* @param b Second angle.
1010
* @returns true if angles are the same, false if they are not
1111
*/
12-
export function areEqual(angle1: number, angle2: number) {
13-
var a1 = noRevolutions(round(angle1));
14-
var a2 = noRevolutions(round(angle2));
15-
16-
return a1 == a2 || a1 + 360 == a2 || a1 - 360 == a2;
12+
export function areEqual(angle1: number, angle2: number, accuracy: number = .0001) {
13+
var a1 = noRevolutions(angle1);
14+
var a2 = noRevolutions(angle2);
15+
var d = noRevolutions(round(a2 - a1, accuracy));
16+
return d == 0;
1717
}
1818

1919
/**

‎src/core/break.ts

Copy file name to clipboardExpand all lines: src/core/break.ts
+5-3Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ module MakerJs.path {
2323
}
2424

2525
function getAngleStrictlyBetweenArcAngles() {
26-
var endAngle = angle.ofArcEnd(arc);
26+
var startAngle = angle.noRevolutions(arc.startAngle);
27+
var endAngle = startAngle + angle.ofArcEnd(arc) - arc.startAngle;
28+
2729
var tries = [0, 1, -1];
2830
for (var i = 0; i < tries.length; i++) {
2931
var add = + 360 * tries[i];
30-
if (measure.isBetween(angleAtBreakPoint + add, arc.startAngle, endAngle, true)) {
31-
return angleAtBreakPoint + add;
32+
if (measure.isBetween(angleAtBreakPoint + add, startAngle, endAngle, true)) {
33+
return arc.startAngle + angleAtBreakPoint + add - startAngle;
3234
}
3335
}
3436
return null;

‎src/core/combine.ts

Copy file name to clipboardExpand all lines: src/core/combine.ts
+65-33Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@ module MakerJs.model {
66
* @private
77
*/
88
function getNonZeroSegments(pathToSegment: IPath, breakPoint: IPoint): IPath[] {
9+
var segmentType = pathToSegment.type;
910
var segment1 = cloneObject<IPath>(pathToSegment);
1011
var segment2 = path.breakAtPoint(segment1, breakPoint);
1112

1213
if (segment2) {
1314
var segments: IPath[] = [segment1, segment2];
1415
for (var i = 2; i--;) {
15-
if (round(measure.pathLength(segments[i]), .00001) == 0) {
16+
if (round(measure.pathLength(segments[i]), .0001) == 0) {
1617
return null;
1718
}
1819
}
1920
return segments;
21+
} else if (segmentType == pathType.Circle) {
22+
return [segment1];
2023
}
2124
return null;
2225
}
@@ -26,7 +29,7 @@ module MakerJs.model {
2629
*/
2730
function breakAlongForeignPath(segments: ICrossedPathSegment[], overlappedSegments: ICrossedPathSegment[], foreignPath: IPath) {
2831

29-
if (path.areEqual(segments[0].path, foreignPath)) {
32+
if (path.areEqual(segments[0].path, foreignPath, .0001)) {
3033
segments[0].overlapped = true;
3134
segments[0].duplicate = true;
3235

@@ -70,13 +73,20 @@ module MakerJs.model {
7073
if (subSegments) {
7174
segments[i].path = subSegments[0];
7275

73-
var newSegment = { path: subSegments[1], overlapped: segments[i].overlapped, uniqueForeignIntersectionPoints: [] };
76+
if (subSegments[1]) {
77+
var newSegment: ICrossedPathSegment = {
78+
path: subSegments[1],
79+
pathId: segments[0].pathId,
80+
overlapped: segments[i].overlapped,
81+
uniqueForeignIntersectionPoints: []
82+
};
7483

75-
if (segments[i].overlapped) {
76-
overlappedSegments.push(newSegment);
77-
}
84+
if (segments[i].overlapped) {
85+
overlappedSegments.push(newSegment);
86+
}
7887

79-
segments.push(newSegment);
88+
segments.push(newSegment);
89+
}
8090

8191
//re-check this segment for another deep intersection
8292
i--;
@@ -94,7 +104,7 @@ module MakerJs.model {
94104

95105
function addUniquePoint(pointToAdd: IPoint) {
96106
for (var i = 0; i < pointArray.length; i++) {
97-
if (point.areEqualRounded(pointArray[i], pointToAdd)) {
107+
if (point.areEqual(pointArray[i], pointToAdd, .000000001)) {
98108
return;
99109
}
100110
}
@@ -112,7 +122,7 @@ module MakerJs.model {
112122
/**
113123
* @private
114124
*/
115-
function checkInsideForeignPath(segment: IPathInside, foreignPath: IPath, farPoint: IPoint = [7654321, 1234567]) {
125+
function checkIntersectsForeignPath(segment: IPathInside, foreignPath: IPath, foreignPathId: string, farPoint: IPoint = [7654321, 1234567]) {
116126
var origin = point.middle(segment.path);
117127
var lineToFarPoint = new paths.Line(origin, farPoint);
118128
var farInt = path.intersection(lineToFarPoint, foreignPath);
@@ -133,7 +143,7 @@ module MakerJs.model {
133143
function checkInsideForeignModel(segment: IPathInside, modelToIntersect: IModel, farPoint?: IPoint) {
134144
walkPaths(modelToIntersect, function (mx: IModel, pathId2: string, path2: IPath) {
135145
if (path2) {
136-
checkInsideForeignPath(segment, path2, farPoint);
146+
checkIntersectsForeignPath(segment, path2, pathId2, farPoint);
137147
}
138148
});
139149
}
@@ -171,16 +181,15 @@ module MakerJs.model {
171181
* @private
172182
*/
173183
interface ICrossedPathSegment extends IPathInside {
184+
pathId: string;
174185
overlapped: boolean;
175186
duplicate?: boolean;
176187
}
177188

178189
/**
179190
* @private
180191
*/
181-
interface ICrossedPath {
182-
modelContext: IModel;
183-
pathId: string;
192+
interface ICrossedPath extends IRefPathIdInModel {
184193
segments: ICrossedPathSegment[];
185194
}
186195

@@ -192,10 +201,20 @@ module MakerJs.model {
192201
overlappedSegments: ICrossedPathSegment[];
193202
}
194203

204+
/**
205+
* Break a model's paths everywhere they intersect with another path.
206+
*
207+
* @param modelToBreak The model containing paths to be broken.
208+
* @param modelToIntersect Optional model containing paths to look for intersection, or else the modelToBreak will be used.
209+
*/
210+
export function breakPathsAtIntersections(modelToBreak: IModel, modelToIntersect?: IModel) {
211+
breakAllPathsAtIntersections(modelToBreak, modelToIntersect || modelToBreak, false);
212+
}
213+
195214
/**
196215
* @private
197216
*/
198-
function breakAllPathsAtIntersections(modelToBreak: IModel, modelToIntersect: IModel, farPoint: IPoint): ICombinedModel {
217+
function breakAllPathsAtIntersections(modelToBreak: IModel, modelToIntersect: IModel, checkIsInside: boolean, farPoint?: IPoint): ICombinedModel {
199218

200219
var crossedPaths: ICrossedPath[] = [];
201220
var overlappedSegments: ICrossedPathSegment[] = [];
@@ -207,6 +226,7 @@ module MakerJs.model {
207226
//clone this path and make it the first segment
208227
var segment: ICrossedPathSegment = {
209228
path: cloneObject<IPath>(path1),
229+
pathId: pathId1,
210230
overlapped: false,
211231
uniqueForeignIntersectionPoints: []
212232
};
@@ -219,14 +239,16 @@ module MakerJs.model {
219239

220240
//keep breaking the segments anywhere they intersect with paths of the other model
221241
walkPaths(modelToIntersect, function (mx: IModel, pathId2: string, path2: IPath) {
222-
if (path2) {
242+
if (path2 && path1 !== path2) {
223243
breakAlongForeignPath(thisPath.segments, overlappedSegments, path2);
224244
}
225245
});
226246

227-
//check each segment whether it is inside or outside
228-
for (var i = 0; i < thisPath.segments.length; i++) {
229-
checkInsideForeignModel(thisPath.segments[i], modelToIntersect);
247+
if (checkIsInside) {
248+
//check each segment whether it is inside or outside
249+
for (var i = 0; i < thisPath.segments.length; i++) {
250+
checkInsideForeignModel(thisPath.segments[i], modelToIntersect, farPoint);
251+
}
230252
}
231253

232254
crossedPaths.push(thisPath);
@@ -238,10 +260,10 @@ module MakerJs.model {
238260
/**
239261
* @private
240262
*/
241-
function checkForEqualOverlaps(crossedPathsA: ICrossedPathSegment[], crossedPathsB: ICrossedPathSegment[]) {
263+
function checkForEqualOverlaps(crossedPathsA: ICrossedPathSegment[], crossedPathsB: ICrossedPathSegment[], pointMatchingDistance: number) {
242264

243265
function compareSegments(segment1: ICrossedPathSegment, segment2: ICrossedPathSegment) {
244-
if (path.areEqual(segment1.path, segment2.path)) {
266+
if (path.areEqual(segment1.path, segment2.path, pointMatchingDistance)) {
245267
segment1.duplicate = segment2.duplicate = true;
246268
}
247269
}
@@ -261,16 +283,16 @@ module MakerJs.model {
261283
/**
262284
* @private
263285
*/
264-
function addOrDeleteSegments(crossedPath: ICrossedPath, includeInside: boolean, includeOutside: boolean, keepDuplicates?: boolean) {
286+
function addOrDeleteSegments(crossedPath: ICrossedPath, includeInside: boolean, includeOutside: boolean, keepDuplicates: boolean) {
265287

266-
function addSegment(model: IModel, pathIdBase: string, segment: ICrossedPathSegment) {
267-
var id = getSimilarPathId(model, pathIdBase);
268-
model.paths[id] = segment.path;
288+
function addSegment(modelContext: IModel, pathIdBase: string, segment: ICrossedPathSegment) {
289+
var id = getSimilarPathId(modelContext, pathIdBase);
290+
modelContext.paths[id] = segment.path;
269291
}
270292

271-
function checkAddSegment(model: IModel, pathIdBase: string, segment: ICrossedPathSegment) {
293+
function checkAddSegment(modelContext: IModel, pathIdBase: string, segment: ICrossedPathSegment) {
272294
if (segment.isInside && includeInside || !segment.isInside && includeOutside) {
273-
addSegment(model, pathIdBase, segment);
295+
addSegment(modelContext, pathIdBase, segment);
274296
}
275297
}
276298

@@ -289,7 +311,7 @@ module MakerJs.model {
289311
}
290312

291313
/**
292-
* Combine 2 models. The models should be originated.
314+
* Combine 2 models. The models should be originated, and every path within each model should be part of a loop.
293315
*
294316
* @param modelA First model to combine.
295317
* @param modelB Second model to combine.
@@ -300,19 +322,29 @@ module MakerJs.model {
300322
* @param keepDuplicates Flag to include paths which are duplicate in both models.
301323
* @param farPoint Optional point of reference which is outside the bounds of both models.
302324
*/
303-
export function combine(modelA: IModel, modelB: IModel, includeAInsideB: boolean = false, includeAOutsideB: boolean = true, includeBInsideA: boolean = false, includeBOutsideA: boolean = true, keepDuplicates: boolean = true, farPoint?: IPoint) {
325+
export function combine(modelA: IModel, modelB: IModel, includeAInsideB: boolean = false, includeAOutsideB: boolean = true, includeBInsideA: boolean = false, includeBOutsideA: boolean = true, options?: ICombineOptions) {
304326

305-
var pathsA = breakAllPathsAtIntersections(modelA, modelB, farPoint);
306-
var pathsB = breakAllPathsAtIntersections(modelB, modelA, farPoint);
327+
var opts: ICombineOptions = {
328+
trimDeadEnds: true,
329+
pointMatchingDistance: .005
330+
};
331+
extendObject(opts, options);
307332

308-
checkForEqualOverlaps(pathsA.overlappedSegments, pathsB.overlappedSegments);
333+
var pathsA = breakAllPathsAtIntersections(modelA, modelB, true, opts.farPoint);
334+
var pathsB = breakAllPathsAtIntersections(modelB, modelA, true, opts.farPoint);
335+
336+
checkForEqualOverlaps(pathsA.overlappedSegments, pathsB.overlappedSegments, opts.pointMatchingDistance);
309337

310338
for (var i = 0; i < pathsA.crossedPaths.length; i++) {
311-
addOrDeleteSegments(pathsA.crossedPaths[i], includeAInsideB, includeAOutsideB, keepDuplicates);
339+
addOrDeleteSegments(pathsA.crossedPaths[i], includeAInsideB, includeAOutsideB, true);
312340
}
313341

314342
for (var i = 0; i < pathsB.crossedPaths.length; i++) {
315-
addOrDeleteSegments(pathsB.crossedPaths[i], includeBInsideA, includeBOutsideA);
343+
addOrDeleteSegments(pathsB.crossedPaths[i], includeBInsideA, includeBOutsideA, false);
344+
}
345+
346+
if (opts.trimDeadEnds) {
347+
removeDeadEnds(<IModel>{ models: { modelA: modelA, modelB: modelB } });
316348
}
317349
}
318350

‎src/core/exporter.ts

Copy file name to clipboardExpand all lines: src/core/exporter.ts
+6-2Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,17 @@ module MakerJs.exporter {
7676

7777
if (modelToExport.paths) {
7878
for (var id in modelToExport.paths) {
79-
this.exportPath(id, modelToExport.paths[id], newOffset, modelToExport.layer);
79+
var currPath = modelToExport.paths[id];
80+
if (!currPath) continue;
81+
this.exportPath(id, currPath, newOffset, modelToExport.layer);
8082
}
8183
}
8284

8385
if (modelToExport.models) {
8486
for (var id in modelToExport.models) {
85-
this.exportModel(id, modelToExport.models[id], newOffset);
87+
var currModel = modelToExport.models[id];
88+
if (!currModel) continue;
89+
this.exportModel(id, currModel, newOffset);
8690
}
8791
}
8892

‎src/core/fillet.ts

Copy file name to clipboardExpand all lines: src/core/fillet.ts
+7-7Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ module MakerJs.path {
6363
/**
6464
* @private
6565
*/
66-
function getMatchingPointProperties(path1: IPath, path2: IPath): IMatchPointProperty[] {
66+
function getMatchingPointProperties(path1: IPath, path2: IPath, options?: IPointMatchOptions): IMatchPointProperty[] {
6767
var path1Properties = getPointProperties(path1);
6868
var path2Properties = getPointProperties(path2);
6969

@@ -80,7 +80,7 @@ module MakerJs.path {
8080
}
8181

8282
function check(i1: number, i2: number) {
83-
if (point.areEqualRounded(path1Properties[i1].point, path2Properties[i2].point)) {
83+
if (point.areEqual(path1Properties[i1].point, path2Properties[i2].point, .0001)) {
8484
result = [
8585
makeMatch(path1, path1Properties, i1),
8686
makeMatch(path2, path2Properties, i2)
@@ -110,7 +110,7 @@ module MakerJs.path {
110110

111111
properties[i].shardPoint = circleIntersection.intersectionPoints[0];
112112

113-
if (point.areEqualRounded(properties[i].point, circleIntersection.intersectionPoints[0], options.accuracy)) {
113+
if (point.areEqual(properties[i].point, circleIntersection.intersectionPoints[0], .0001)) {
114114
if (circleIntersection.intersectionPoints.length > 1) {
115115
properties[i].shardPoint = circleIntersection.intersectionPoints[1];
116116
} else {
@@ -296,12 +296,12 @@ module MakerJs.path {
296296
if (isPathLine(line1) && isPathLine(line2) && filletRadius && filletRadius > 0) {
297297

298298
var opts: IPointMatchOptions = {
299-
accuracy: .0001
299+
pointMatchingDistance: .005
300300
};
301301
extendObject(opts, options);
302302

303303
//first find the common point
304-
var commonProperty = getMatchingPointProperties(line1, line2);
304+
var commonProperty = getMatchingPointProperties(line1, line2, options);
305305
if (commonProperty) {
306306

307307
//get the ratio comparison of the two lines
@@ -360,12 +360,12 @@ module MakerJs.path {
360360
if (path1 && path2 && filletRadius && filletRadius > 0) {
361361

362362
var opts: IPointMatchOptions = {
363-
accuracy: .0001
363+
pointMatchingDistance: .005
364364
};
365365
extendObject(opts, options);
366366

367367
//first find the common point
368-
var commonProperty = getMatchingPointProperties(path1, path2);
368+
var commonProperty = getMatchingPointProperties(path1, path2, options);
369369
if (commonProperty) {
370370

371371
//since arcs can curl beyond, we need a local reference point.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.