Skip to content

Commit 02f8306

Browse files
committed
Merge pull request #64 from Microsoft/dev
Dev
2 parents 5001f4c + 1bd9dad commit 02f8306

File tree

14 files changed

+379
-117
lines changed

14 files changed

+379
-117
lines changed

README.md

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,54 @@
11
# Maker.js
22

3-
Maker.js, a Microsoft Garage project, is a JavaScript library for creating and sharing modular line drawings for CNC and laser cutters. Maker.js runs in both Node.js and web browsers.
3+
Maker.js, a Microsoft Garage project, is a JavaScript library for creating line drawings for CNC and laser cutters. It runs in both Node.js and web browsers.
44

5-
[About](http://microsoft.github.io/maker.js/about/) - [Blog](http://microsoft.github.io/maker.js/) - [Demos](http://microsoft.github.io/maker.js/demos/) - [Documentation](http://microsoft.github.io/maker.js/docs/) - [Discussion](https://gitter.im/Microsoft/maker.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5+
[Demos](http://microsoft.github.io/maker.js/demos/) - [Documentation](http://microsoft.github.io/maker.js/docs/)
6+
7+
## Features
8+
9+
### Drawing with JavaScript code
10+
11+
Draw using three primitive paths: [Line, Circle, and Arc](http://microsoft.github.io/maker.js/docs/basic-drawing/#Paths).
12+
13+
Paths can be [grouped into Models](http://microsoft.github.io/maker.js/docs/basic-drawing/#Models) to form more complex drawings.
14+
15+
Behind the scenes, drawings are a [simple Javascript object](http://microsoft.github.io/maker.js/docs/basic-drawing/#It%27s%20Just%20JSON) which can be serialized / deserialized conventionally with JSON.
16+
17+
Other people's Models can be imported, [modified](http://microsoft.github.io/maker.js/docs/intermediate-drawing/#Modifying%20models), and re-exported.
18+
19+
Models can be [scaled](http://microsoft.github.io/maker.js/docs/intermediate-drawing/#Scaling), [measured](http://microsoft.github.io/maker.js/docs/api/modules/makerjs.measure.html#modelextents), and [converted to different unit systems](http://microsoft.github.io/maker.js/docs/basic-drawing/#Units).
20+
21+
Models can be [rotated](http://microsoft.github.io/maker.js/docs/intermediate-drawing/#Rotating) or [mirrored](http://microsoft.github.io/maker.js/docs/intermediate-drawing/#Mirroring).
22+
23+
Find [intersection points or intersection angles](http://microsoft.github.io/maker.js/docs/api/modules/makerjs.path.html#intersection) of paths.
24+
25+
Easily add a curvature at the joint between any 2 paths, using a [traditional fillet](http://microsoft.github.io/maker.js/docs/api/modules/makerjs.path.html#fillet) or a [dogbone fillet](http://microsoft.github.io/maker.js/docs/api/modules/makerjs.path.html#dogbone).
26+
27+
[Combine models](http://microsoft.github.io/maker.js/docs/api/modules/makerjs.model.html#combine) with boolean operations to get unions, intersections, or punches.
28+
29+
[Detect loops](http://microsoft.github.io/maker.js/docs/api/modules/makerjs.model.html#findloops) formed by paths connecting end to end.
30+
31+
### Output formats
32+
33+
2D: [DXF](http://microsoft.github.io/maker.js/docs/api/modules/makerjs.exporter.html#todxf), [SVG](http://microsoft.github.io/maker.js/docs/api/modules/makerjs.exporter.html#tosvg)
34+
35+
3D: [OpenJsCad script](http://microsoft.github.io/maker.js/docs/api/modules/makerjs.exporter.html#toopenjscad), [STL](http://microsoft.github.io/maker.js/docs/api/modules/makerjs.exporter.html#tostl) (Must include [OpenJsCad](http://joostn.github.io/OpenJsCad/) or [openjscad-csg](https://www.npmjs.com/package/openjscad-csg))
36+
37+
### Built-in models
38+
39+
* Bolt Circle
40+
* Bolt Rectangle
41+
* Connect the dots
42+
* Dome
43+
* Oval
44+
* OvalArc
45+
* Polygon
46+
* Rectangle
47+
* Ring
48+
* RoundRectangle
49+
* S curve
50+
* Square
51+
* Star
652

753
## Getting Started
854

debug/viewer.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,18 @@ var Viewer = {
168168
break;
169169

170170
case 'bool':
171-
input = new makerjs.exporter.XmlTag('input', {
171+
172+
var checkboxAttrs = {
172173
id: id,
173174
type: 'checkbox',
174-
checked: attrs.value ? 'checked' : '',
175175
onchange: 'Viewer.Refresh(' + i + ', this.checked)'
176-
});
176+
};
177+
178+
if (attrs.value) {
179+
checkboxAttrs['checked'] = true;
180+
}
181+
182+
input = new makerjs.exporter.XmlTag('input', checkboxAttrs);
177183

178184
break;
179185
}

index.js

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ var MakerJs;
506506
var pointAngleInRadians = MakerJs.angle.ofPointInRadians(rotationOrigin, pointToRotate);
507507
var d = MakerJs.measure.pointDistance(rotationOrigin, pointToRotate);
508508
var rotatedPoint = fromPolar(pointAngleInRadians + MakerJs.angle.toRadians(angleInDegrees), d);
509-
return add(rotationOrigin, rotatedPoint);
509+
return rounded(add(rotationOrigin, rotatedPoint));
510510
}
511511
point.rotate = rotate;
512512
/**
@@ -1334,6 +1334,10 @@ var MakerJs;
13341334
* @param farPoint Optional point of reference which is outside the bounds of both models.
13351335
*/
13361336
function combine(modelA, modelB, includeAInsideB, includeAOutsideB, includeBInsideA, includeBOutsideA, keepDuplicates, farPoint) {
1337+
if (includeAInsideB === void 0) { includeAInsideB = false; }
1338+
if (includeAOutsideB === void 0) { includeAOutsideB = true; }
1339+
if (includeBInsideA === void 0) { includeBInsideA = false; }
1340+
if (includeBOutsideA === void 0) { includeBOutsideA = true; }
13371341
if (keepDuplicates === void 0) { keepDuplicates = true; }
13381342
var pathsA = breakAllPathsAtIntersections(modelA, modelB, farPoint);
13391343
var pathsB = breakAllPathsAtIntersections(modelB, modelA, farPoint);
@@ -2352,7 +2356,7 @@ var MakerJs;
23522356
/**
23532357
* @private
23542358
*/
2355-
function populateShardPointsFromReferenceCircle(filletRadius, center, properties) {
2359+
function populateShardPointsFromReferenceCircle(filletRadius, center, properties, options) {
23562360
var referenceCircle = new MakerJs.paths.Circle(center, filletRadius);
23572361
//get reference circle intersection points
23582362
for (var i = 0; i < 2; i++) {
@@ -2361,7 +2365,7 @@ var MakerJs;
23612365
return false;
23622366
}
23632367
properties[i].shardPoint = circleIntersection.intersectionPoints[0];
2364-
if (MakerJs.point.areEqualRounded(properties[i].point, circleIntersection.intersectionPoints[0], .0001)) {
2368+
if (MakerJs.point.areEqualRounded(properties[i].point, circleIntersection.intersectionPoints[0], options.accuracy)) {
23652369
if (circleIntersection.intersectionPoints.length > 1) {
23662370
properties[i].shardPoint = circleIntersection.intersectionPoints[1];
23672371
}
@@ -2510,8 +2514,12 @@ var MakerJs;
25102514
* @param line2 Second line to fillet, which will be modified to fit the fillet.
25112515
* @returns Arc path object of the new fillet.
25122516
*/
2513-
function dogbone(line1, line2, filletRadius) {
2517+
function dogbone(line1, line2, filletRadius, options) {
25142518
if (MakerJs.isPathLine(line1) && MakerJs.isPathLine(line2) && filletRadius && filletRadius > 0) {
2519+
var opts = {
2520+
accuracy: .0001
2521+
};
2522+
MakerJs.extendObject(opts, options);
25152523
//first find the common point
25162524
var commonProperty = getMatchingPointProperties(line1, line2);
25172525
if (commonProperty) {
@@ -2523,7 +2531,7 @@ var MakerJs;
25232531
//use the bisection theorem to get the angle bisecting the lines
25242532
var bisectionAngle = MakerJs.angle.ofPointInDegrees(commonProperty[0].point, midRatioPoint);
25252533
var center = MakerJs.point.add(commonProperty[0].point, MakerJs.point.fromPolar(MakerJs.angle.toRadians(bisectionAngle), filletRadius));
2526-
if (!populateShardPointsFromReferenceCircle(filletRadius, center, commonProperty)) {
2534+
if (!populateShardPointsFromReferenceCircle(filletRadius, center, commonProperty, opts)) {
25272535
return null;
25282536
}
25292537
//get the angles of the fillet and a function which clips the path to the fillet.
@@ -2557,14 +2565,18 @@ var MakerJs;
25572565
* @param path2 Second path to fillet, which will be modified to fit the fillet.
25582566
* @returns Arc path object of the new fillet.
25592567
*/
2560-
function fillet(path1, path2, filletRadius) {
2568+
function fillet(path1, path2, filletRadius, options) {
25612569
if (path1 && path2 && filletRadius && filletRadius > 0) {
2570+
var opts = {
2571+
accuracy: .0001
2572+
};
2573+
MakerJs.extendObject(opts, options);
25622574
//first find the common point
25632575
var commonProperty = getMatchingPointProperties(path1, path2);
25642576
if (commonProperty) {
25652577
//since arcs can curl beyond, we need a local reference point.
25662578
//An intersection with a circle of the same radius as the desired fillet should suffice.
2567-
if (!populateShardPointsFromReferenceCircle(filletRadius, commonProperty[0].point, commonProperty)) {
2579+
if (!populateShardPointsFromReferenceCircle(filletRadius, commonProperty[0].point, commonProperty, opts)) {
25682580
return null;
25692581
}
25702582
//get "parallel" guidelines
@@ -2685,7 +2697,16 @@ var MakerJs;
26852697
/**
26862698
* @private
26872699
*/
2688-
function follow(connections, loops) {
2700+
function collectLoop(loop, loops, detach) {
2701+
loops.push(loop);
2702+
if (detach) {
2703+
detachLoop(loop);
2704+
}
2705+
}
2706+
/**
2707+
* @private
2708+
*/
2709+
function follow(connections, loops, detach) {
26892710
//for a given point, follow the paths that connect to each other to form loops
26902711
for (var p in connections) {
26912712
var linkedPaths = connections[p];
@@ -2699,7 +2720,7 @@ var MakerJs;
26992720
while (true) {
27002721
var currPath = currLink.path;
27012722
currPath.reversed = currLink.reversed;
2702-
var id = model.getSimilarPathId(loopModel, currLink.id);
2723+
var id = model.getSimilarPathId(loopModel, currPath.primePathId);
27032724
loopModel.paths[id] = currPath;
27042725
if (!connections[currLink.nextConnection])
27052726
break;
@@ -2710,7 +2731,7 @@ var MakerJs;
27102731
currLink = nextLink;
27112732
if (currLink.path === firstLink.path) {
27122733
//loop is closed
2713-
loops.push(loopModel);
2734+
collectLoop(loopModel, loops, detach);
27142735
break;
27152736
}
27162737
}
@@ -2721,15 +2742,19 @@ var MakerJs;
27212742
* Find paths that have common endpoints and form loops.
27222743
*
27232744
* @param modelContext The model to search for loops.
2724-
* @param accuracy Optional exemplar of number of decimal places.
2725-
* @returns A new model with child models ranked according to their containment within other found loops. The paths of models will be IPathDirectional.
2745+
* @param options Optional options object.
2746+
* @returns A new model with child models ranked according to their containment within other found loops. The paths of models will be IPathDirectionalWithPrimeContext.
27262747
*/
2727-
function findLoops(modelContext, accuracy) {
2748+
function findLoops(modelContext, options) {
27282749
var loops = [];
27292750
var connections = {};
27302751
var result = { models: {} };
2752+
var opts = {
2753+
accuracy: .0001
2754+
};
2755+
MakerJs.extendObject(opts, options);
27312756
function getLinkedPathsOnConnectionPoint(p) {
2732-
var serializedPoint = MakerJs.point.serialize(p, accuracy);
2757+
var serializedPoint = MakerJs.point.serialize(p, opts.accuracy);
27332758
if (!(serializedPoint in connections)) {
27342759
connections[serializedPoint] = [];
27352760
}
@@ -2754,31 +2779,32 @@ var MakerJs;
27542779
if (!pathContext)
27552780
return;
27562781
var safePath = MakerJs.cloneObject(pathContext);
2782+
safePath.primePathId = pathId;
2783+
safePath.primeModel = modelContext;
27572784
//circles are loops by nature
27582785
if (safePath.type == MakerJs.pathType.Circle) {
27592786
var loopModel = {
27602787
paths: {},
27612788
insideCount: 0
27622789
};
27632790
loopModel.paths[pathId] = safePath;
2764-
loops.push(loopModel);
2791+
collectLoop(loopModel, loops, opts.removeFromOriginal);
27652792
}
27662793
else {
27672794
//gather both endpoints from all non-circle segments
27682795
safePath.endPoints = MakerJs.point.fromPathEnds(safePath);
27692796
for (var i = 2; i--;) {
27702797
var linkedPath = {
2771-
id: pathId,
27722798
path: safePath,
2773-
nextConnection: MakerJs.point.serialize(safePath.endPoints[1 - i], accuracy),
2799+
nextConnection: MakerJs.point.serialize(safePath.endPoints[1 - i], opts.accuracy),
27742800
reversed: i != 0
27752801
};
27762802
getLinkedPathsOnConnectionPoint(safePath.endPoints[i]).push(linkedPath);
27772803
}
27782804
}
27792805
});
27802806
//follow paths to find loops
2781-
follow(connections, loops);
2807+
follow(connections, loops, opts.removeFromOriginal);
27822808
//now we have all loops, we need to see which are inside of each other
27832809
spin(function (firstLoop) {
27842810
var firstPath = getFirstPathFromModel(firstLoop);
@@ -2802,6 +2828,21 @@ var MakerJs;
28022828
return result;
28032829
}
28042830
model.findLoops = findLoops;
2831+
/**
2832+
* Remove all paths in a loop model from the model(s) which contained them.
2833+
*
2834+
* @param loopToDetach The model to search for loops.
2835+
*/
2836+
function detachLoop(loopToDetach) {
2837+
for (var id in loopToDetach.paths) {
2838+
var pathDirectionalWithOriginalContext = loopToDetach.paths[id];
2839+
var primeModel = pathDirectionalWithOriginalContext.primeModel;
2840+
if (primeModel && primeModel.paths && pathDirectionalWithOriginalContext.primePathId) {
2841+
delete primeModel.paths[pathDirectionalWithOriginalContext.primePathId];
2842+
}
2843+
}
2844+
}
2845+
model.detachLoop = detachLoop;
28052846
})(model = MakerJs.model || (MakerJs.model = {}));
28062847
})(MakerJs || (MakerJs = {}));
28072848
var MakerJs;
@@ -3017,7 +3058,7 @@ var MakerJs;
30173058
accuracy: .0001
30183059
};
30193060
MakerJs.extendObject(opts, options);
3020-
var loops = MakerJs.model.findLoops(modelToExport, opts.accuracy);
3061+
var loops = MakerJs.model.findLoops(modelToExport, opts);
30213062
while (depthModel = loops.models[depth]) {
30223063
var union = '';
30233064
for (var modelId in depthModel.models) {

package.json

Lines 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.2",
3+
"version": "0.5.3",
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/combine.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ module MakerJs.model {
300300
* @param keepDuplicates Flag to include paths which are duplicate in both models.
301301
* @param farPoint Optional point of reference which is outside the bounds of both models.
302302
*/
303-
export function combine(modelA: IModel, modelB: IModel, includeAInsideB: boolean, includeAOutsideB: boolean, includeBInsideA: boolean, includeBOutsideA: boolean, keepDuplicates: boolean = true, farPoint?: IPoint) {
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) {
304304

305305
var pathsA = breakAllPathsAtIntersections(modelA, modelB, farPoint);
306306
var pathsB = breakAllPathsAtIntersections(modelB, modelA, farPoint);

src/core/fillet.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ module MakerJs.path {
9898
/**
9999
* @private
100100
*/
101-
function populateShardPointsFromReferenceCircle(filletRadius: number, center: IPoint, properties: IMatchPointProperty[]): boolean {
101+
function populateShardPointsFromReferenceCircle(filletRadius: number, center: IPoint, properties: IMatchPointProperty[], options: IPointMatchOptions): boolean {
102102
var referenceCircle = new paths.Circle(center, filletRadius);
103103

104104
//get reference circle intersection points
@@ -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], .0001)) {
113+
if (point.areEqualRounded(properties[i].point, circleIntersection.intersectionPoints[0], options.accuracy)) {
114114
if (circleIntersection.intersectionPoints.length > 1) {
115115
properties[i].shardPoint = circleIntersection.intersectionPoints[1];
116116
} else {
@@ -291,10 +291,15 @@ module MakerJs.path {
291291
* @param line2 Second line to fillet, which will be modified to fit the fillet.
292292
* @returns Arc path object of the new fillet.
293293
*/
294-
export function dogbone(line1: IPathLine, line2: IPathLine, filletRadius: number): IPathArc {
294+
export function dogbone(line1: IPathLine, line2: IPathLine, filletRadius: number, options?: IPointMatchOptions): IPathArc {
295295

296296
if (isPathLine(line1) && isPathLine(line2) && filletRadius && filletRadius > 0) {
297297

298+
var opts: IPointMatchOptions = {
299+
accuracy: .0001
300+
};
301+
extendObject(opts, options);
302+
298303
//first find the common point
299304
var commonProperty = getMatchingPointProperties(line1, line2);
300305
if (commonProperty) {
@@ -311,7 +316,7 @@ module MakerJs.path {
311316

312317
var center = point.add(commonProperty[0].point, point.fromPolar(angle.toRadians(bisectionAngle), filletRadius));
313318

314-
if (!populateShardPointsFromReferenceCircle(filletRadius, center, commonProperty)) {
319+
if (!populateShardPointsFromReferenceCircle(filletRadius, center, commonProperty, opts)) {
315320
return null;
316321
}
317322

@@ -350,17 +355,22 @@ module MakerJs.path {
350355
* @param path2 Second path to fillet, which will be modified to fit the fillet.
351356
* @returns Arc path object of the new fillet.
352357
*/
353-
export function fillet(path1: IPath, path2: IPath, filletRadius: number): IPathArc {
358+
export function fillet(path1: IPath, path2: IPath, filletRadius: number, options?: IPointMatchOptions): IPathArc {
354359

355360
if (path1 && path2 && filletRadius && filletRadius > 0) {
356361

362+
var opts: IPointMatchOptions = {
363+
accuracy: .0001
364+
};
365+
extendObject(opts, options);
366+
357367
//first find the common point
358368
var commonProperty = getMatchingPointProperties(path1, path2);
359369
if (commonProperty) {
360370

361371
//since arcs can curl beyond, we need a local reference point.
362372
//An intersection with a circle of the same radius as the desired fillet should suffice.
363-
if (!populateShardPointsFromReferenceCircle(filletRadius, commonProperty[0].point, commonProperty)) {
373+
if (!populateShardPointsFromReferenceCircle(filletRadius, commonProperty[0].point, commonProperty, opts)) {
364374
return null;
365375
}
366376

0 commit comments

Comments
 (0)