diff --git a/packages/core/tests/attributes.test.mjs b/packages/core/tests/attributes.test.mjs index 1144b0e8f4e..318d56e52e0 100644 --- a/packages/core/tests/attributes.test.mjs +++ b/packages/core/tests/attributes.test.mjs @@ -6,78 +6,81 @@ const expect = chai.expect const newAttr = () => new Point(0, 0).attributes; const a = newAttr(); -it("Should set an attribute", () => { - a.set('hold', 'me') - expect(a.get("hold")).to.equal('me'); -}); -it("Should remove an attribute", () => { - a.remove('hold') - expect(a.get("hold")).to.equal(false); -}); +describe('Attributes', () => { + it("Should set an attribute", () => { + a.set('hold', 'me') + expect(a.get("hold")).to.equal('me'); + }); -it("Should only set an unset attribute", () => { - a.setIfUnset('hold', 'me') - expect(a.get("hold")).to.equal('me'); - a.setIfUnset('hold', 'thatDudeOverThere') - expect(a.get("hold")).to.equal('me'); -}); + it("Should remove an attribute", () => { + a.remove('hold') + expect(a.get("hold")).to.equal(false); + }); -it("Should return false when getting an unset attribute", () => { - let a = newAttr(); - expect(a.get("test")).to.equal(false); -}); + it("Should only set an unset attribute", () => { + a.setIfUnset('hold', 'me') + expect(a.get("hold")).to.equal('me'); + a.setIfUnset('hold', 'thatDudeOverThere') + expect(a.get("hold")).to.equal('me'); + }); -it("Should render attributes correctly", () => { - let a = newAttr() - .set("class", "test") - .add("class", "render") - .set("transform", "scale(1)"); - expect(a.render()).to.equal(' class="test render" transform="scale(1)"'); -}); + it("Should return false when getting an unset attribute", () => { + let a = newAttr(); + expect(a.get("test")).to.equal(false); + }); -it("Should render attributes with given prefix only", () => { - let a = newAttr() - .set("class", "test") - .add("class", "render") - .add("data-text", "foo") - .add("data-text", "bar") - .add("data-mode", "test") - .set("transform", "scale(1)"); - expect(a.renderIfPrefixIs("data-")).to.equal(' text="foo bar" mode="test"'); -}); + it("Should render attributes correctly", () => { + let a = newAttr() + .set("class", "test") + .add("class", "render") + .set("transform", "scale(1)"); + expect(a.render()).to.equal(' class="test render" transform="scale(1)"'); + }); -it("Should return attributes as array", () => { - let a = newAttr() - .set("class", "test") - .add("class", "render"); - expect(JSON.stringify(a.getAsArray("class"))).to.equal( - JSON.stringify(["test", "render"]) - ); - expect(a.getAsArray("nope")).to.equal(false); -}); + it("Should render attributes with given prefix only", () => { + let a = newAttr() + .set("class", "test") + .add("class", "render") + .add("data-text", "foo") + .add("data-text", "bar") + .add("data-mode", "test") + .set("transform", "scale(1)"); + expect(a.renderIfPrefixIs("data-")).to.equal(' text="foo bar" mode="test"'); + }); -it("Should render attributes as CSS", () => { - let a = newAttr() - .set("line-height", 1.2) - .add("border", "1px solid red"); - expect(a.renderAsCss()).to.equal(" line-height:1.2; border:1px solid red;"); -}); + it("Should return attributes as array", () => { + let a = newAttr() + .set("class", "test") + .add("class", "render"); + expect(JSON.stringify(a.getAsArray("class"))).to.equal( + JSON.stringify(["test", "render"]) + ); + expect(a.getAsArray("nope")).to.equal(false); + }); -it("Should return attributes as props and filter a prefix", () => { - const a = newAttr() - .set("line-height", 1.2) - .add("border", "1px solid red") - .set("data-text", "This is a test") - .set("data-text-class", "center"); - const props = a.asPropsIfPrefixIs('data-') - expect(props.text).to.equal("This is a test"); - expect(props['text-class']).to.equal("center"); -}); + it("Should render attributes as CSS", () => { + let a = newAttr() + .set("line-height", 1.2) + .add("border", "1px solid red"); + expect(a.renderAsCss()).to.equal(" line-height:1.2; border:1px solid red;"); + }); -it("Should return attributes as props and handle special class case", () => { - const a = newAttr().set("class", "fabric"); - const props = a.asPropsIfPrefixIs('') - expect(props.className).to.equal("fabric"); -}); + it("Should return attributes as props and filter a prefix", () => { + const a = newAttr() + .set("line-height", 1.2) + .add("border", "1px solid red") + .set("data-text", "This is a test") + .set("data-text-class", "center"); + const props = a.asPropsIfPrefixIs('data-') + expect(props.text).to.equal("This is a test"); + expect(props['text-class']).to.equal("center"); + }); + + it("Should return attributes as props and handle special class case", () => { + const a = newAttr().set("class", "fabric"); + const props = a.asPropsIfPrefixIs('') + expect(props.className).to.equal("fabric"); + }); +}) diff --git a/packages/core/tests/design.test.mjs b/packages/core/tests/design.test.mjs index b497d48c88e..b5152e99918 100644 --- a/packages/core/tests/design.test.mjs +++ b/packages/core/tests/design.test.mjs @@ -3,344 +3,229 @@ import freesewing from "./dist/index.mjs" const expect = chai.expect -it("Design constructor should return pattern constructor", () => { - let design = new freesewing.Design({ - foo: "bar", - options: { - constant: 2, - percentage: { pct: 30, min: 0, max: 100 } - } +describe('Design', () => { + it("Design constructor should return pattern constructor", () => { + const design = new freesewing.Design({ + foo: "bar", + options: { + constant: 2, + percentage: { pct: 30, min: 0, max: 100 } + } + }); + + const pattern = new design(); + expect(pattern.width).to.equal(0); + expect(pattern.height).to.equal(0); + expect(pattern.settings.complete).to.equal(true); + expect(pattern.parts).to.eql({}); + expect(pattern.settings.units).to.equal("metric"); + expect(pattern.config.foo).to.equal("bar"); + expect(pattern.settings.options.constant).to.equal(2); + expect(pattern.settings.options.percentage).to.equal(0.3); }); - let pattern = new design(); - expect(pattern.width).to.equal(0); - expect(pattern.height).to.equal(0); - expect(pattern.settings.complete).to.equal(true); - expect(pattern.parts).to.eql({}); - expect(pattern.settings.units).to.equal("metric"); - expect(pattern.config.foo).to.equal("bar"); - expect(pattern.settings.options.constant).to.equal(2); - expect(pattern.settings.options.percentage).to.equal(0.3); -}); - -it("Design constructor should load single plugin (legacy)", () => { - let plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); + it("Design constructor should load single plugin", () => { + let plugin = { + name: "example", + version: 1, + hooks: { + preRender: function(svg, attributes) { + svg.attributes.add("freesewing:plugin-example", version); + } } - } - }; + }; - let design = new freesewing.Design({}, plugin); - let pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(1); -}); - -it("Design constructor should load single plugin (2022)", () => { - let plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - - let design = new freesewing.Design({plugins: plugin}); - let pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(1); -}); - -it("Design constructor should load array of plugins (legacy)", () => { - let plugin1 = { - name: "example1", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example1", version); - } - } - }; - let plugin2 = { - name: "example2", - version: 2, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example2", version); - } - } - }; - - let design = new freesewing.Design({}, [plugin1, plugin2]); - let pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(2); -}); - -it("Design constructor should load array of plugins (2022)", () => { - let plugin1 = { - name: "example1", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example1", version); - } - } - }; - let plugin2 = { - name: "example2", - version: 2, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example2", version); - } - } - }; - - let design = new freesewing.Design( { plugins: [plugin1, plugin2] }); - let pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(2); -}); - -it("Design constructor should load conditional plugin (legacy)", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition = () => true - const design = new freesewing.Design({}, [], { plugin, condition }); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(1); -}); - -it("Design constructor should load conditional plugin (2022)", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition = () => true - const design = new freesewing.Design({ conditionalPlugins: { plugin, condition } }); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(1); -}); - -it("Design constructor should not load conditional plugin (legacy)", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition = () => false - const design = new freesewing.Design({}, [], { plugin, condition }); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(0); -}); - -it("Design constructor should not load conditional plugin (2022)", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition = () => false - const design = new freesewing.Design({ conditionalPlugins: { plugin, condition } }); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(0); -}); - -it("Design constructor should load multiple conditional plugins (legacy)", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition1 = () => true - const condition2 = () => false - const design = new freesewing.Design({}, [], [ - { plugin, condition: condition1 }, - { plugin, condition: condition2 }, - ]); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(1); -}); - -it("Design constructor should load multiple conditional plugins (2022)", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition1 = () => true - const condition2 = () => false - const design = new freesewing.Design({ conditionalPlugins: [ - { plugin, condition: condition1 }, - { plugin, condition: condition2 }, - ]}); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(1); -}); - -it("Design constructor should construct basic part order", () => { - let design = new freesewing.Design({ - dependencies: { step4: "step3" }, - inject: { step4: "step3" }, - parts: ["step1", "step2"] + let design = new freesewing.Design({plugins: plugin}); + let pattern = new design(); + expect(pattern.hooks.preRender.length).to.equal(1); }); - let pattern = new design().init(); - expect(pattern.config.draftOrder[0]).to.equal("step3"); - expect(pattern.config.draftOrder[1]).to.equal("step4"); - expect(pattern.config.draftOrder[2]).to.equal("step1"); - expect(pattern.config.draftOrder[3]).to.equal("step2"); -}); -it("Design constructor should not require depencies for injected parts", () => { - let design = new freesewing.Design({ - inject: { step4: "step3" }, - parts: ["step1", "step2"] - }); - let pattern = new design().init(); - expect(pattern.config.draftOrder[0]).to.equal("step3"); - expect(pattern.config.draftOrder[1]).to.equal("step4"); - expect(pattern.config.draftOrder[2]).to.equal("step1"); - expect(pattern.config.draftOrder[3]).to.equal("step2"); -}); - -it("Design constructor should handle parts and dependencies overlap", () => { - let design = new freesewing.Design({ - inject: { step4: "step3" }, - parts: ["step1", "step2", "step3"] - }); - let pattern = new design().init(); - expect(pattern.config.draftOrder[0]).to.equal("step3"); - expect(pattern.config.draftOrder[1]).to.equal("step4"); - expect(pattern.config.draftOrder[2]).to.equal("step1"); - expect(pattern.config.draftOrder[3]).to.equal("step2"); -}); - -it("Design constructor discover all parts", () => { - let design = new freesewing.Design({ - inject: { - step4: "step3", - step5: "step4", - step6: "step5", - step7: "step6", - step8: "step7", - step9: "step8", - step10: "step9", - step11: "step10" - }, - hide: [], - parts: ["step1", "step2"] - }); - let pattern = new design().init(); - expect(pattern.config.draftOrder[0]).to.equal("step3"); - expect(pattern.config.draftOrder[1]).to.equal("step4"); - expect(pattern.config.draftOrder[2]).to.equal("step5"); - expect(pattern.config.draftOrder[3]).to.equal("step6"); - expect(pattern.config.draftOrder[4]).to.equal("step7"); - expect(pattern.config.draftOrder[5]).to.equal("step8"); - expect(pattern.config.draftOrder[6]).to.equal("step9"); - expect(pattern.config.draftOrder[7]).to.equal("step10"); - expect(pattern.config.draftOrder[8]).to.equal("step11"); - expect(pattern.config.draftOrder[9]).to.equal("step1"); - expect(pattern.config.draftOrder[10]).to.equal("step2"); -}); - -it("Design constructor should handle Simon", () => { - let design = new freesewing.Design({ - dependencies: { - sleeve: ["front", "back"] - }, - inject: { - frontBase: "base", - backBase: "base", - back: "backBase", - front: "frontBase", - frontRight: "front", - frontLeft: "front", - buttonPlacket: "front", - buttonholePlacket: "front", - yoke: "backBase", - sleeve: "sleeveBase" - }, - parts: [ - "collarStand", - "collar", - "sleevePlacketUnderlap", - "sleevePlacketOverlap", - "cuff" - ], - hide: ["base", "frontBase", "front", "backBase", "sleeveBase"] - }); - let pattern = new design().init(); -}); - -it("Pattern constructor should add default hide() method to options", () => { - const design = new freesewing.Design({ - foo: "bar", - options: { - constant: 2, - percentage: { pct: 30, min: 0, max: 100 }, - degree: { deg: 5, min: 0, max: 10 }, - withHide: { - dflt: 'foo', - list: ['foo', 'bar'], - hide: ({ options }) => (options.degree < 6) + it("Design constructor should load array of plugins", () => { + let plugin1 = { + name: "example1", + version: 1, + hooks: { + preRender: function(svg, attributes) { + svg.attributes.add("freesewing:plugin-example1", version); + } } - } + }; + let plugin2 = { + name: "example2", + version: 2, + hooks: { + preRender: function(svg, attributes) { + svg.attributes.add("freesewing:plugin-example2", version); + } + } + }; + + let design = new freesewing.Design( { plugins: [plugin1, plugin2] }); + let pattern = new design(); + expect(pattern.hooks.preRender.length).to.equal(2); + }); + + it("Design constructor should load conditional plugin", () => { + const plugin = { + name: "example", + version: 1, + hooks: { + preRender: function(svg, attributes) { + svg.attributes.add("freesewing:plugin-example", version); + } + } + }; + const condition = () => true + const design = new freesewing.Design({ conditionalPlugins: { plugin, condition } }); + const pattern = new design(); + expect(pattern.hooks.preRender.length).to.equal(1); + }); + + it("Design constructor should not load conditional plugin", () => { + const plugin = { + name: "example", + version: 1, + hooks: { + preRender: function(svg, attributes) { + svg.attributes.add("freesewing:plugin-example", version); + } + } + }; + const condition = () => false + const design = new freesewing.Design({ conditionalPlugins: { plugin, condition } }); + const pattern = new design(); + expect(pattern.hooks.preRender.length).to.equal(0); + }); + + it("Design constructor should load multiple conditional plugins", () => { + const plugin = { + name: "example", + version: 1, + hooks: { + preRender: function(svg, attributes) { + svg.attributes.add("freesewing:plugin-example", version); + } + } + }; + const condition1 = () => true + const condition2 = () => false + const design = new freesewing.Design({ conditionalPlugins: [ + { plugin, condition: condition1 }, + { plugin, condition: condition2 }, + ]}); + const pattern = new design(); + expect(pattern.hooks.preRender.length).to.equal(1); + }); + + /* + it("Design constructor should not require depencies for injected parts", () => { + let design = new freesewing.Design({ + inject: { step4: "step3" }, + parts: ["step1", "step2"] + }); + let pattern = new design().init(); + expect(pattern.config.draftOrder[0]).to.equal("step3"); + expect(pattern.config.draftOrder[1]).to.equal("step4"); + expect(pattern.config.draftOrder[2]).to.equal("step1"); + expect(pattern.config.draftOrder[3]).to.equal("step2"); + }); + + it("Design constructor should handle parts and dependencies overlap", () => { + let design = new freesewing.Design({ + inject: { step4: "step3" }, + parts: ["step1", "step2", "step3"] + }); + let pattern = new design().init(); + expect(pattern.config.draftOrder[0]).to.equal("step3"); + expect(pattern.config.draftOrder[1]).to.equal("step4"); + expect(pattern.config.draftOrder[2]).to.equal("step1"); + expect(pattern.config.draftOrder[3]).to.equal("step2"); + }); + + it("Design constructor discover all parts", () => { + let design = new freesewing.Design({ + inject: { + step4: "step3", + step5: "step4", + step6: "step5", + step7: "step6", + step8: "step7", + step9: "step8", + step10: "step9", + step11: "step10" + }, + hide: [], + parts: ["step1", "step2"] + }); + let pattern = new design().init(); + expect(pattern.config.draftOrder[0]).to.equal("step3"); + expect(pattern.config.draftOrder[1]).to.equal("step4"); + expect(pattern.config.draftOrder[2]).to.equal("step5"); + expect(pattern.config.draftOrder[3]).to.equal("step6"); + expect(pattern.config.draftOrder[4]).to.equal("step7"); + expect(pattern.config.draftOrder[5]).to.equal("step8"); + expect(pattern.config.draftOrder[6]).to.equal("step9"); + expect(pattern.config.draftOrder[7]).to.equal("step10"); + expect(pattern.config.draftOrder[8]).to.equal("step11"); + expect(pattern.config.draftOrder[9]).to.equal("step1"); + expect(pattern.config.draftOrder[10]).to.equal("step2"); + }); + + it("Design constructor should handle Simon", () => { + let design = new freesewing.Design({ + dependencies: { + sleeve: ["front", "back"] + }, + inject: { + frontBase: "base", + backBase: "base", + back: "backBase", + front: "frontBase", + frontRight: "front", + frontLeft: "front", + buttonPlacket: "front", + buttonholePlacket: "front", + yoke: "backBase", + sleeve: "sleeveBase" + }, + parts: [ + "collarStand", + "collar", + "sleevePlacketUnderlap", + "sleevePlacketOverlap", + "cuff" + ], + hide: ["base", "frontBase", "front", "backBase", "sleeveBase"] + }); + let pattern = new design().init(); + }); + + */ + + it("Pattern constructor should add default hide() method to options", () => { + const design = new freesewing.Design({ + foo: "bar", + options: { + constant: 2, + percentage: { pct: 30, min: 0, max: 100 }, + degree: { deg: 5, min: 0, max: 10 }, + withHide: { + dflt: 'foo', + list: ['foo', 'bar'], + hide: ({ options }) => (options.degree < 6) + } + } + }) + + const pattern = new design().init(); + expect(typeof pattern.config.options.constant === 'number').to.be.true + expect(typeof pattern.config.options.percentage === 'object').to.be.true + expect(typeof pattern.config.options.degree === 'object').to.be.true + expect(typeof pattern.config.options.withHide === 'object').to.be.true + expect(pattern.config.options.percentage.hide()).to.be.false + expect(pattern.config.options.degree.hide()).to.be.false + expect(pattern.config.options.withHide.hide(pattern.settings)).to.be.true }) - const pattern = new design().init(); - expect(typeof pattern.config.options.constant === 'number').to.be.true - expect(typeof pattern.config.options.percentage === 'object').to.be.true - expect(typeof pattern.config.options.degree === 'object').to.be.true - expect(typeof pattern.config.options.withHide === 'object').to.be.true - expect(pattern.config.options.percentage.hide()).to.be.false - expect(pattern.config.options.degree.hide()).to.be.false - expect(pattern.config.options.withHide.hide(pattern.settings)).to.be.true }) -it("Should warn when passing plugins both as parameter and in the config", () => { - const design = new freesewing.Design({plugins: [{}]}, {}); - expect(design.config.warnings.length).to.equal(2) - expect(design.config.warnings[0]).to.equal('Passing plugins to the Design constructor both as a second parameter and in the config is unsupported') - expect(design.config.warnings[1]).to.equal('Ignoring plugins passed as parameter. Only config.plugins will be used.') -}) - -it("Should warn when passing conditionalPlugins both as parameter and in the config", () => { - const design = new freesewing.Design({conditionalPlugins: [{}]}, false, {}); - expect(design.config.warnings.length).to.equal(2) - expect(design.config.warnings[0]).to.equal('Passing conditionalPlugins to the Design constructor both as a third parameter and in the config is unsupported.') - expect(design.config.warnings[1]).to.equal('Ignoring conditionalPlugins passes as parameter. Only config.conditionalPlugins will be used.') -}) - - diff --git a/packages/core/tests/hooks.test.mjs b/packages/core/tests/hooks.test.mjs index bf4b8b82b1b..5f256cd37df 100644 --- a/packages/core/tests/hooks.test.mjs +++ b/packages/core/tests/hooks.test.mjs @@ -3,18 +3,20 @@ import { Pattern } from "./dist/index.mjs" const expect = chai.expect -it("Should contain all hooks", () => { - let pattern = new Pattern(); - let h = pattern.hooks; - let test = { - preDraft: [], - postDraft: [], - postLayout: [], - preSample: [], - postSample: [], - preRender: [], - postRender: [], - insertText: [], - }; - expect(h).to.eql(test); +describe('Hooks', () => { + it("Should contain all hooks", () => { + const pattern = new Pattern(); + const h = pattern.hooks; + const test = { + preDraft: [], + postDraft: [], + postLayout: [], + preSample: [], + postSample: [], + preRender: [], + postRender: [], + insertText: [], + }; + expect(h).to.eql(test); + }); }); diff --git a/packages/core/tests/part.test.mjs b/packages/core/tests/part.test.mjs index b2926bcc6fb..ec714049a26 100644 --- a/packages/core/tests/part.test.mjs +++ b/packages/core/tests/part.test.mjs @@ -4,461 +4,462 @@ import freesewing from "./dist/index.mjs" const expect = chai.expect describe('Part', () => { -it("Svg constructor should initialize object", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - expect(part.paths).to.eql({}); - expect(part.snippets).to.eql({}); - expect(part.freeId).to.equal(0); - expect(part.topLeft).to.equal(false); - expect(part.bottomRight).to.equal(false); - expect(part.width).to.equal(false); - expect(part.height).to.equal(false); - expect(part.render).to.equal(true); -}); + it("Svg constructor should initialize object", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + expect(part.paths).to.eql({}); + expect(part.snippets).to.eql({}); + expect(part.freeId).to.equal(0); + expect(part.topLeft).to.equal(false); + expect(part.bottomRight).to.equal(false); + expect(part.width).to.equal(false); + expect(part.height).to.equal(false); + expect(part.render).to.equal(true); + }); -it("Should return a function from macroClosure", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - expect(typeof part.macroClosure()).to.equal("function"); -}); + it("Should return a function from macroClosure", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + expect(typeof part.macroClosure()).to.equal("function"); + }); -it("Should not run an unknown macro", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - let macro = part.macroClosure(); - expect(macro("unknown")).to.equal(undefined); -}); + it("Should not run an unknown macro", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + let macro = part.macroClosure(); + expect(macro("unknown")).to.equal(undefined); + }); -it("Should register and run a macro", () => { - let pattern = new freesewing.Pattern(); - let plugin = { - name: "test", - version: "0.1-test", - macros: { - test: function(so) { - let points = this.points; - points.macro = new this.Point(so.x, so.y); + it("Should register and run a macro", () => { + let pattern = new freesewing.Pattern(); + let plugin = { + name: "test", + version: "0.1-test", + macros: { + test: function(so) { + let points = this.points; + points.macro = new this.Point(so.x, so.y); + } } + }; + pattern.use(plugin); + let part = new pattern.Part(); + let macro = part.macroClosure(); + macro("test", { x: 123, y: 456 }); + expect(part.points.macro.x).to.equal(123); + expect(part.points.macro.y).to.equal(456); + }); + + it("Should return a free ID", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + let free = part.getId(); + expect(part.getId()).to.equal("" + (parseInt(free) + 1)); + }); + + it("Should return a function from unitsClosure", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + expect(typeof part.unitsClosure()).to.equal("function"); + }); + + it("Should convert units", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + let units = part.unitsClosure(); + expect(units(123.456)).to.equal("12.35cm"); + expect(part.units(123.456)).to.equal("12.35cm"); + }); + + it("Should set part attributes", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + part.attr("foo", "bar"); + expect(part.attributes.get("foo")).to.equal("bar"); + part.attr("foo", "baz"); + expect(part.attributes.get("foo")).to.equal("bar baz"); + part.attr("foo", "schmoo", true); + expect(part.attributes.get("foo")).to.equal("schmoo"); + }); + + it("Should inject a part", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + part.points.a = new part.Point(12, 23); + part.points.b = new part.Point(10, 10); + part.points.c = new part.Point(20, 20); + part.paths.bar = new freesewing.Path() + .move(part.points.a) + .line(part.points.b) + .curve(part.points.c, part.points.b, part.points.a) + const { Snippet, snippets } = part.shorthand() + snippets.d = new Snippet('notch', part.points.a) + let test = new pattern.Part(); + test.inject(part); + expect(test.points.a.x).to.equal(12); + expect(test.points.a.y).to.equal(23); + expect(test.paths.bar.ops.length).to.equal(3) + for (let i=0;i<3;i++) { + expect(test.paths.bar.ops[i].type).to.equal(part.paths.bar.ops[i].type) + expect(test.paths.bar.ops[i].to.x).to.equal(part.paths.bar.ops[i].to.x) + expect(test.paths.bar.ops[i].to.y).to.equal(part.paths.bar.ops[i].to.y) } - }; - pattern.use(plugin); - let part = new pattern.Part(); - let macro = part.macroClosure(); - macro("test", { x: 123, y: 456 }); - expect(part.points.macro.x).to.equal(123); - expect(part.points.macro.y).to.equal(456); -}); + expect(test.snippets.d.anchor.x).to.equal(part.points.a.x) + expect(test.snippets.d.anchor.y).to.equal(part.points.a.y) + }); -it("Should return a free ID", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - let free = part.getId(); - expect(part.getId()).to.equal("" + (parseInt(free) + 1)); -}); + it("Should return shorthand", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + pattern.settings.paperless = true; + let part = new pattern.Part(); + let short = part.shorthand(); + expect(short.complete).to.equal(true); + expect(short.paperless).to.equal(true); + }); -it("Should return a function from unitsClosure", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - expect(typeof part.unitsClosure()).to.equal("function"); -}); + it("Should raise a warning when setting a non-Point value in points", () => { + const pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + const part = new pattern.Part(); + const { points } = part.shorthand() + points.a = 'banana' + expect(pattern.events.warning.length).to.equal(4) + expect(pattern.events.warning[0]).to.equal('`points.a` was set with a value that is not a `Point` object') + expect(pattern.events.warning[1]).to.equal('`points.a` was set with a `x` parameter that is not a `number`') + expect(pattern.events.warning[2]).to.equal('`points.a` was set with a `y` parameter that is not a `number`') + }); -it("Should convert units", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - let units = part.unitsClosure(); - expect(units(123.456)).to.equal("12.35cm"); - expect(part.units(123.456)).to.equal("12.35cm"); -}); + it("Should raise a warning when setting a non-Snippet value in snippets", () => { + const pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + const part = new pattern.Part(); + const { snippets } = part.shorthand() + snippets.a = 'banana' + expect(pattern.events.warning.length).to.equal(4) + expect(pattern.events.warning[0]).to.equal('`snippets.a` was set with a value that is not a `Snippet` object') + expect(pattern.events.warning[1]).to.equal('`snippets.a` was set with a `def` parameter that is not a `string`') + expect(pattern.events.warning[2]).to.equal('`snippets.a` was set with an `anchor` parameter that is not a `Point`') + }); -it("Should set part attributes", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.attr("foo", "bar"); - expect(part.attributes.get("foo")).to.equal("bar"); - part.attr("foo", "baz"); - expect(part.attributes.get("foo")).to.equal("bar baz"); - part.attr("foo", "schmoo", true); - expect(part.attributes.get("foo")).to.equal("schmoo"); -}); + it("Should calculate the part boundary with default margin", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + let part = new pattern.Part(); + let short = part.shorthand(); + part.points.from = new short.Point(123, 456); + part.points.to = new short.Point(19, 76); + part.paths.test = new short.Path() + .move(part.points.from) + .line(part.points.to); + let boundary = part.boundary(); + expect(boundary.topLeft.x).to.equal(17); + expect(boundary.topLeft.y).to.equal(74); + expect(boundary.bottomRight.x).to.equal(125); + expect(boundary.bottomRight.y).to.equal(458); + boundary = part.boundary(); + expect(boundary.width).to.equal(108); + expect(boundary.height).to.equal(384); + }); -it("Should inject a part", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.points.a = new part.Point(12, 23); - part.points.b = new part.Point(10, 10); - part.points.c = new part.Point(20, 20); - part.paths.bar = new freesewing.Path() - .move(part.points.a) - .line(part.points.b) - .curve(part.points.c, part.points.b, part.points.a) - const { Snippet, snippets } = part.shorthand() - snippets.d = new Snippet('notch', part.points.a) - let test = new pattern.Part(); - test.inject(part); - expect(test.points.a.x).to.equal(12); - expect(test.points.a.y).to.equal(23); - expect(test.paths.bar.ops.length).to.equal(3) - for (let i=0;i<3;i++) { - expect(test.paths.bar.ops[i].type).to.equal(part.paths.bar.ops[i].type) - expect(test.paths.bar.ops[i].to.x).to.equal(part.paths.bar.ops[i].to.x) - expect(test.paths.bar.ops[i].to.y).to.equal(part.paths.bar.ops[i].to.y) - } - expect(test.snippets.d.anchor.x).to.equal(part.points.a.x) - expect(test.snippets.d.anchor.y).to.equal(part.points.a.y) -}); + it("Should calculate the part boundary with custom margin", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + pattern.settings.margin = 5; + let part = new pattern.Part(); + let short = part.shorthand(); + part.points.from = new short.Point(123, 456); + part.points.to = new short.Point(19, 76); + part.paths.test = new short.Path() + .move(part.points.from) + .line(part.points.to); + let boundary = part.boundary(); + expect(boundary.topLeft.x).to.equal(14); + expect(boundary.topLeft.y).to.equal(71); + expect(boundary.bottomRight.x).to.equal(128); + expect(boundary.bottomRight.y).to.equal(461); + boundary = part.boundary(); + expect(boundary.width).to.equal(114); + expect(boundary.height).to.equal(390); + }); -it("Should return shorthand", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - pattern.settings.paperless = true; - let part = new pattern.Part(); - let short = part.shorthand(); - expect(short.complete).to.equal(true); - expect(short.paperless).to.equal(true); -}); + it("Should calculate the part boundary for paperless", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + pattern.settings.margin = 5; + pattern.settings.paperless = true; + let part = new pattern.Part(); + let short = part.shorthand(); + part.points.from = new short.Point(123, 456); + part.points.to = new short.Point(19, 76); + part.paths.test = new short.Path() + .move(part.points.from) + .line(part.points.to); + let boundary = part.boundary(); + expect(boundary.topLeft.x).to.equal(9); + expect(boundary.topLeft.y).to.equal(66); + expect(boundary.bottomRight.x).to.equal(133); + expect(boundary.bottomRight.y).to.equal(466); + boundary = part.boundary(); + expect(boundary.width).to.equal(124); + expect(boundary.height).to.equal(400); + }); -it("Should raise a warning when setting a non-Point value in points", () => { - const pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - const part = new pattern.Part(); - const { points } = part.shorthand() - points.a = 'banana' - expect(pattern.events.warning.length).to.equal(4) - expect(pattern.events.warning[0]).to.equal('`points.a` was set with a value that is not a `Point` object') - expect(pattern.events.warning[1]).to.equal('`points.a` was set with a `x` parameter that is not a `number`') - expect(pattern.events.warning[2]).to.equal('`points.a` was set with a `y` parameter that is not a `number`') -}); + it("Should stack a part", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + let part = new pattern.Part(); + let short = part.shorthand(); + part.points.from = new short.Point(123, 456); + part.points.to = new short.Point(19, 76); + part.paths.test = new short.Path() + .move(part.points.from) + .line(part.points.to); + part.stack(); + expect(part.attributes.get("transform")).to.equal("translate(-17, -74)"); + }); -it("Should raise a warning when setting a non-Snippet value in snippets", () => { - const pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - const part = new pattern.Part(); - const { snippets } = part.shorthand() - snippets.a = 'banana' - expect(pattern.events.warning.length).to.equal(4) - expect(pattern.events.warning[0]).to.equal('`snippets.a` was set with a value that is not a `Snippet` object') - expect(pattern.events.warning[1]).to.equal('`snippets.a` was set with a `def` parameter that is not a `string`') - expect(pattern.events.warning[2]).to.equal('`snippets.a` was set with an `anchor` parameter that is not a `Point`') -}); + it("Should only stack a part if needed", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + let part = new pattern.Part(); + let short = part.shorthand(); + part.points.from = new short.Point(2, 2); + part.points.to = new short.Point(19, 76); + part.paths.test = new short.Path() + .move(part.points.from) + .line(part.points.to); + part.stack(); + expect(part.attributes.get("transform")).to.equal(false); + part.stack(); + expect(part.attributes.get("transform")).to.equal(false); + }); -it("Should calculate the part boundary with default margin", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - let part = new pattern.Part(); - let short = part.shorthand(); - part.points.from = new short.Point(123, 456); - part.points.to = new short.Point(19, 76); - part.paths.test = new short.Path() - .move(part.points.from) - .line(part.points.to); - let boundary = part.boundary(); - expect(boundary.topLeft.x).to.equal(17); - expect(boundary.topLeft.y).to.equal(74); - expect(boundary.bottomRight.x).to.equal(125); - expect(boundary.bottomRight.y).to.equal(458); - boundary = part.boundary(); - expect(boundary.width).to.equal(108); - expect(boundary.height).to.equal(384); -}); + it("Should run hooks", () => { + let count = 0 + const pattern = new freesewing.Pattern() + const part = new pattern.Part(); + part.hooks.preDraft = [{ method: function(p) { count++ }} ] + part.runHooks('preDraft') + expect(count).to.equal(1); + }); -it("Should calculate the part boundary with custom margin", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - pattern.settings.margin = 5; - let part = new pattern.Part(); - let short = part.shorthand(); - part.points.from = new short.Point(123, 456); - part.points.to = new short.Point(19, 76); - part.paths.test = new short.Path() - .move(part.points.from) - .line(part.points.to); - let boundary = part.boundary(); - expect(boundary.topLeft.x).to.equal(14); - expect(boundary.topLeft.y).to.equal(71); - expect(boundary.bottomRight.x).to.equal(128); - expect(boundary.bottomRight.y).to.equal(461); - boundary = part.boundary(); - expect(boundary.width).to.equal(114); - expect(boundary.height).to.equal(390); -}); + it("Should get the units closure to raise a debug when passing a non-number", () => { + const pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + pattern.settings.debug = true + const part = new pattern.Part(); + const short = part.shorthand(); + short.units('a') + expect(pattern.events.debug.length).to.equal(1) + expect(pattern.events.debug[0]).to.equal('Calling `units(value)` but `value` is not a number (`string`)') + }); -it("Should calculate the part boundary for paperless", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - pattern.settings.margin = 5; - pattern.settings.paperless = true; - let part = new pattern.Part(); - let short = part.shorthand(); - part.points.from = new short.Point(123, 456); - part.points.to = new short.Point(19, 76); - part.paths.test = new short.Path() - .move(part.points.from) - .line(part.points.to); - let boundary = part.boundary(); - expect(boundary.topLeft.x).to.equal(9); - expect(boundary.topLeft.y).to.equal(66); - expect(boundary.bottomRight.x).to.equal(133); - expect(boundary.bottomRight.y).to.equal(466); - boundary = part.boundary(); - expect(boundary.width).to.equal(124); - expect(boundary.height).to.equal(400); -}); - -it("Should stack a part", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - let part = new pattern.Part(); - let short = part.shorthand(); - part.points.from = new short.Point(123, 456); - part.points.to = new short.Point(19, 76); - part.paths.test = new short.Path() - .move(part.points.from) - .line(part.points.to); - part.stack(); - expect(part.attributes.get("transform")).to.equal("translate(-17, -74)"); -}); - -it("Should only stack a part if needed", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - let part = new pattern.Part(); - let short = part.shorthand(); - part.points.from = new short.Point(2, 2); - part.points.to = new short.Point(19, 76); - part.paths.test = new short.Path() - .move(part.points.from) - .line(part.points.to); - part.stack(); - expect(part.attributes.get("transform")).to.equal(false); - part.stack(); - expect(part.attributes.get("transform")).to.equal(false); -}); - -it("Should run hooks", () => { - let count = 0 - const pattern = new freesewing.Pattern() - const part = new pattern.Part(); - part.hooks.preDraft = [{ method: function(p) { count++ }} ] - part.runHooks('preDraft') - expect(count).to.equal(1); -}); - -it("Should get the units closure to raise a debug when passing a non-number", () => { - const pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - const part = new pattern.Part(); - const short = part.shorthand(); - short.units('a') - expect(pattern.events.debug.length).to.equal(1) - expect(pattern.events.debug[0]).to.equal('Calling `units(value)` but `value` is not a number (`string`)') -}); - -it("Should generate the part transforms", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - let part = new pattern.Part(); - let short = part.shorthand(); - part.points.from = new short.Point(2, 2); - part.points.to = new short.Point(19, 76); - part.paths.test = new short.Path() - .move(part.points.from) - .line(part.points.to); - part.stack(); - part.generateTransform({ - move: { - x: 10, - y: 20 - } - }) - expect(part.attributes.list.transform.length).to.equal(1) - expect(part.attributes.list.transform[0]).to.equal('translate(10 20)') -}); + it("Should generate the part transforms", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + let part = new pattern.Part(); + let short = part.shorthand(); + part.points.from = new short.Point(2, 2); + part.points.to = new short.Point(19, 76); + part.paths.test = new short.Path() + .move(part.points.from) + .line(part.points.to); + part.stack(); + part.generateTransform({ + move: { + x: 10, + y: 20 + } + }) + expect(part.attributes.list.transform.length).to.equal(1) + expect(part.attributes.list.transform[0]).to.equal('translate(10 20)') + }); -it("Should add the part cut", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.addCut(4, 'fabric', true) - expect(part.cut.materials.fabric.cut).to.equal(4) - expect(part.cut.materials.fabric.identical).to.equal(true) - part.addCut() - expect(part.cut.materials.fabric.cut).to.equal(2) - expect(part.cut.materials.fabric.identical).to.equal(false) -}); - -it("Should generate an error if cut is not a number", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.addCut('a', 'fabric', true) - expect(pattern.events.error.length).to.equal(1) - expect(pattern.events.error[0]).to.equal('Tried to set cut to a value that is not a positive integer') -}); - -it("Should generate an warning if material is not a string", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.addCut(3, 4) - expect(pattern.events.warning.length).to.equal(1) - expect(pattern.events.warning[0]).to.equal('Tried to set material to a value that is not a string') -}); - -it("Should generate an error when removing a material that is not set (through addCut)", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.addCut(4, 'fabric', true) - part.addCut(false, 'lining') - expect(pattern.events.warning.length).to.equal(1) - expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set') -}); - -it("Should remove the part cut through addCut", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.addCut(4, 'fabric', true) - part.addCut(false, 'fabric') - expect(typeof part.cut.materials.fabric).to.equal('undefined') -}); - -it("Should remove the part cut through removeCut", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.addCut(4, 'fabric', true) - part.removeCut('fabric') - expect(typeof part.cut.materials.fabric).to.equal('undefined') -}); - -it("Should generate an error when removing a material that is not set (through removeCut)", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.addCut(4, 'fabric', true) - part.removeCut('lining') - expect(pattern.events.warning.length).to.equal(1) - expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set') -}); - -it("Should generate an error when removing a material that is not a string (through removeCut)", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.addCut(4, 'fabric', true) - part.removeCut(23) - expect(pattern.events.warning.length).to.equal(1) - expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set') -}); - -it("Should generate a warning when calling removeCut without parameters", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.addCut(4, 'fabric', true) - part.removeCut() - expect(pattern.events.warning.length).to.equal(1) - expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set') -}); - -it("Should set the part grainline", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - expect(part.cut.grain).to.equal(90) - part.setGrain(123) - expect(part.cut.grain).to.equal(123) -}); - -it("Should raise a warning when calling part.setGrain() without any parameters", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.setGrain() - expect(part.cut.grain).to.equal(false) -}); - -it("Should raise an error when calling part.setGrain() with a value that is not a number", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - part.setGrain('a') - expect(part.cut.grain).to.equal(90) - expect(pattern.events.error.length).to.equal(1) - expect(pattern.events.error[0]).to.equal('Called part.setGrain() with a value that is not a number') -}); - -it("Should set and then remove the cutOnFold", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - const { Point } = part.shorthand() - part.setCutOnFold(new Point(2,3), new Point(100,200)) - expect(part.cut.cutOnFold[0].x).to.equal(2) - expect(part.cut.cutOnFold[0].y).to.equal(3) - expect(part.cut.cutOnFold[1].x).to.equal(100) - expect(part.cut.cutOnFold[1].y).to.equal(200) - part.setCutOnFold(false) - expect(typeof part.cut.cutOnFold).to.equal('undefined') -}); - -it("Should raise an error when setting the cutOnFold with a non-Point value", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - const { Point } = part.shorthand() - part.setCutOnFold(new Point(2,3), 12) - expect(pattern.events.error.length).to.equal(1) - expect(pattern.events.error[0]).to.equal('Called part.setCutOnFold() but at least one parameter is not a Point instance') -}); - -describe('isEmpty', () => { - it("Should return true if the part has no paths or snippets", () => { + it("Should add the part cut", () => { let pattern = new freesewing.Pattern(); let part = new pattern.Part(); - expect(part.isEmpty()).to.be.true - }) + part.addCut(4, 'fabric', true) + expect(part.cut.materials.fabric.cut).to.equal(4) + expect(part.cut.materials.fabric.identical).to.equal(true) + part.addCut() + expect(part.cut.materials.fabric.cut).to.equal(2) + expect(part.cut.materials.fabric.identical).to.equal(false) + }); - it("Should return true if the part has paths but they have no length", () => { + it("Should generate an error if cut is not a number", () => { let pattern = new freesewing.Pattern(); let part = new pattern.Part(); - const { Path, paths, Point } = part.shorthand() - paths.seam = new Path() - expect(part.isEmpty()).to.be.true - }) + part.addCut('a', 'fabric', true) + expect(pattern.events.error.length).to.equal(1) + expect(pattern.events.error[0]).to.equal('Tried to set cut to a value that is not a positive integer') + }); - it("Should return true if the part has paths but they don't render", () => { + it("Should generate an warning if material is not a string", () => { let pattern = new freesewing.Pattern(); let part = new pattern.Part(); - const { Path, paths, Point } = part.shorthand() - paths.seam = new Path().move(new Point(0,0)).line(new Point(2,3)).setRender(false) - expect(part.isEmpty()).to.be.true - }) + part.addCut(3, 4) + expect(pattern.events.warning.length).to.equal(1) + expect(pattern.events.warning[0]).to.equal('Tried to set material to a value that is not a string') + }); - it("Should return false if the part has a path with length", () => { + it("Should generate an error when removing a material that is not set (through addCut)", () => { let pattern = new freesewing.Pattern(); let part = new pattern.Part(); - const { Path, paths, Point } = part.shorthand() - paths.seam = new Path().move(new Point(0,0)).line(new Point(2,3)) + part.addCut(4, 'fabric', true) + part.addCut(false, 'lining') + expect(pattern.events.warning.length).to.equal(1) + expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set') + }); - expect(part.isEmpty()).to.be.false - }) - - it("Should return false if the part has a snippet", () => { + it("Should remove the part cut through addCut", () => { let pattern = new freesewing.Pattern(); let part = new pattern.Part(); - const { Point, snippets, Snippet } = part.shorthand() - snippets.test = new Snippet('test', new Point(0,0)) + part.addCut(4, 'fabric', true) + part.addCut(false, 'fabric') + expect(typeof part.cut.materials.fabric).to.equal('undefined') + }); - expect(part.isEmpty()).to.be.false - }) - - it("Should return false if the part has a point that has text", () => { + it("Should remove the part cut through removeCut", () => { let pattern = new freesewing.Pattern(); let part = new pattern.Part(); - const {Point, points} = part.shorthand() - points.test = new Point(0,0) - points.test.attributes.set('data-text', 'text') - expect(part.isEmpty()).to.be.false - }) + part.addCut(4, 'fabric', true) + part.removeCut('fabric') + expect(typeof part.cut.materials.fabric).to.equal('undefined') + }); - it("Should return false if the part has a point that has a circle", () => { + it("Should generate an error when removing a material that is not set (through removeCut)", () => { let pattern = new freesewing.Pattern(); let part = new pattern.Part(); - const {Point, points} = part.shorthand() - points.test = new Point(0,0) - points.test.attributes.set('data-circle', 10) - expect(part.isEmpty()).to.be.false + part.addCut(4, 'fabric', true) + part.removeCut('lining') + expect(pattern.events.warning.length).to.equal(1) + expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set') + }); + + it("Should generate an error when removing a material that is not a string (through removeCut)", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + part.addCut(4, 'fabric', true) + part.removeCut(23) + expect(pattern.events.warning.length).to.equal(1) + expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set') + }); + + it("Should generate a warning when calling removeCut without parameters", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + part.addCut(4, 'fabric', true) + part.removeCut() + expect(pattern.events.warning.length).to.equal(1) + expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set') + }); + + it("Should set the part grainline", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + expect(part.cut.grain).to.equal(90) + part.setGrain(123) + expect(part.cut.grain).to.equal(123) + }); + + it("Should raise a warning when calling part.setGrain() without any parameters", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + part.setGrain() + expect(part.cut.grain).to.equal(false) + }); + + it("Should raise an error when calling part.setGrain() with a value that is not a number", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + part.setGrain('a') + expect(part.cut.grain).to.equal(90) + expect(pattern.events.error.length).to.equal(1) + expect(pattern.events.error[0]).to.equal('Called part.setGrain() with a value that is not a number') + }); + + it("Should set and then remove the cutOnFold", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + const { Point } = part.shorthand() + part.setCutOnFold(new Point(2,3), new Point(100,200)) + expect(part.cut.cutOnFold[0].x).to.equal(2) + expect(part.cut.cutOnFold[0].y).to.equal(3) + expect(part.cut.cutOnFold[1].x).to.equal(100) + expect(part.cut.cutOnFold[1].y).to.equal(200) + part.setCutOnFold(false) + expect(typeof part.cut.cutOnFold).to.equal('undefined') + }); + + it("Should raise an error when setting the cutOnFold with a non-Point value", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + const { Point } = part.shorthand() + part.setCutOnFold(new Point(2,3), 12) + expect(pattern.events.error.length).to.equal(1) + expect(pattern.events.error[0]).to.equal('Called part.setCutOnFold() but at least one parameter is not a Point instance') + }); + + describe('isEmpty', () => { + it("Should return true if the part has no paths or snippets", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + expect(part.isEmpty()).to.be.true + }) + + it("Should return true if the part has paths but they have no length", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + const { Path, paths, Point } = part.shorthand() + paths.seam = new Path() + expect(part.isEmpty()).to.be.true + }) + + it("Should return true if the part has paths but they don't render", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + const { Path, paths, Point } = part.shorthand() + paths.seam = new Path().move(new Point(0,0)).line(new Point(2,3)).setRender(false) + expect(part.isEmpty()).to.be.true + }) + + it("Should return false if the part has a path with length", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + const { Path, paths, Point } = part.shorthand() + paths.seam = new Path().move(new Point(0,0)).line(new Point(2,3)) + + expect(part.isEmpty()).to.be.false + }) + + it("Should return false if the part has a snippet", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + const { Point, snippets, Snippet } = part.shorthand() + snippets.test = new Snippet('test', new Point(0,0)) + + expect(part.isEmpty()).to.be.false + }) + + it("Should return false if the part has a point that has text", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + const {Point, points} = part.shorthand() + points.test = new Point(0,0) + points.test.attributes.set('data-text', 'text') + expect(part.isEmpty()).to.be.false + }) + + it("Should return false if the part has a point that has a circle", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + const {Point, points} = part.shorthand() + points.test = new Point(0,0) + points.test.attributes.set('data-circle', 10) + expect(part.isEmpty()).to.be.false + }) }) -}) }) diff --git a/packages/core/tests/path.test.mjs b/packages/core/tests/path.test.mjs index cb43bc103b1..af90d5529c2 100644 --- a/packages/core/tests/path.test.mjs +++ b/packages/core/tests/path.test.mjs @@ -4,1170 +4,1172 @@ import freesewing from "./dist/index.mjs" const expect = chai.expect const round = freesewing.utils.round -it("Should offset a line", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)); - a.paths.offset = a.paths.line.offset(10); - pattern.render(); - expect(a.paths.offset.bottomRight.x).to.equal(-10); - expect(a.paths.offset.bottomRight.y).to.equal(40); -}); - -it("Should offset a curve", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.curve = new a.Path() - .move(new a.Point(0, 0)) - .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)); - a.paths.offset = a.paths.curve.offset(10); - pattern.render(); - expect(round(a.paths.offset.bottomRight.x)).to.equal(72.18); - expect(round(a.paths.offset.bottomRight.y)).to.equal(38.26); -}); - -it("Should offset a curve where cp1 = start", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.curve = new a.Path() - .move(new a.Point(0, 0)) - .curve(new a.Point(0, 0), new a.Point(123, 34), new a.Point(23, 4)); - a.paths.offset = a.paths.curve.offset(10); - pattern.render(); - expect(round(a.paths.offset.bottomRight.x)).to.equal(72.63); - expect(round(a.paths.offset.bottomRight.y)).to.equal(26.48); -}); - -it("Should offset a curve where cp2 = end", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.curve = new a.Path() - .move(new a.Point(0, 0)) - .curve(new a.Point(40, 0), new a.Point(123, 34), new a.Point(123, 34)) - .close(); - a.paths.offset = a.paths.curve.offset(10); - pattern.render(); - expect(round(a.paths.offset.bottomRight.x)).to.equal(119.26); - expect(round(a.paths.offset.bottomRight.y)).to.equal(43.27); -}); - -it("Should throw error when offsetting line that is no line", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.line = new a.Path().move(new a.Point(0, 40)).line(new a.Point(0, 40)); - expect(() => a.paths.line.offset(10)).to.throw(); -}); - -it("Should return the length of a line", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)); - expect(a.paths.line.length()).to.equal(40); -}); - -it("Should return the length of a curve", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.curve = new a.Path() - .move(new a.Point(0, 0)) - .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)) - .close(); - expect(round(a.paths.curve.length())).to.equal(145.11); -}); - -it("Should return the path start point", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.curve = new a.Path() - .move(new a.Point(123, 456)) - .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)) - .close(); - expect(a.paths.curve.start().x).to.equal(123); - expect(a.paths.curve.start().y).to.equal(456); -}); - -it("Should return the path end point", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.curve = new a.Path() - .move(new a.Point(123, 456)) - .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)); - expect(a.paths.curve.end().x).to.equal(23); - expect(a.paths.curve.end().y).to.equal(4); - a.paths.curve.close(); - expect(a.paths.curve.end().x).to.equal(123); - expect(a.paths.curve.end().y).to.equal(456); -}); - -it("Should calculate that path boundary", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.curve = new a.Path() - .move(new a.Point(123, 456)) - .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)); - a.paths.curve.boundary(); - expect(a.paths.curve.topLeft.x).to.equal(71.6413460920667); - expect(a.paths.curve.topLeft.y).to.equal(4); - a.paths.curve.boundary(); - expect(a.paths.curve.bottomRight.x).to.equal(230); - expect(a.paths.curve.bottomRight.y).to.equal(456); -}); - -it("Should clone a path", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.curve = new a.Path() - .move(new a.Point(123, 456)) - .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)); - let b = a.paths.curve.clone(); - b.boundary(); - expect(b.topLeft.x).to.equal(71.6413460920667); - expect(b.topLeft.y).to.equal(4); - b = b.clone(); - expect(b.bottomRight.x).to.equal(230); - expect(b.bottomRight.y).to.equal(456); -}); - -it("Should join paths", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)); - a.paths.curve = new a.Path() - .move(new a.Point(123, 456)) - .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)); - a.paths.joint = a.paths.curve.join(a.paths.line); - expect(a.paths.joint.ops.length).to.equal(4); -}); - -it("Should throw error when joining a closed paths", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)); - a.paths.curve = new a.Path() - .move(new a.Point(123, 456)) - .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)) - .close(); - expect(() => a.paths.curve.join(a.paths.line)).to.throw(); -}); - -it("Should shift along a line", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)); - expect(a.paths.line.shiftAlong(20).y).to.equal(20); -}); - -it("Should not shift along a path/line if we end up on the end point", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(10, 0)); - expect(a.paths.line.shiftAlong(10).x).to.equal(10); -}); - -it("Should shift along lines", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.line = new a.Path() - .move(new a.Point(0, 0)) - .line(new a.Point(0, 40)) - .line(new a.Point(100, 40)); - expect(a.paths.line.shiftAlong(50).x).to.equal(10); - expect(a.paths.line.shiftAlong(50).y).to.equal(40); -}); - -it("Should shift along curve + line", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.test = new a.Path() - .move(new a.Point(0, 0)) - .line(new a.Point(0, 40)) - .curve(new a.Point(40, 40), new a.Point(40, 0), new a.Point(200, 0)) - .line(new a.Point(200, 400)); - expect(round(a.paths.test.shiftAlong(500).x)).to.equal(200); - expect(round(a.paths.test.shiftAlong(500).y)).to.equal(253.74); -}); - -it("Should throw error when shifting along path further than it's long", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.paths.test = new a.Path() - .move(new a.Point(0, 0)) - .line(new a.Point(0, 40)) - .line(new a.Point(200, 400)); - expect(() => a.paths.test.shiftAlong(500)).to.throw(); -}); - -it("Should shift along with sufficient precision", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.paths.test = new a.Path() - .move(new a.Point(0, 0)) - .curve(new a.Point(123, 123), new a.Point(-123, 456), new a.Point(456, -123)) - a.points.a = a.paths.test.shiftAlong(100) - a.points.b = a.paths.test.reverse().shiftAlong(a.paths.test.length()-100) - expect(a.points.a.dist(a.points.b)).to.below(0.05); -}); - -it("Should shift fraction with sufficient precision", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.paths.test = new a.Path() - .move(new a.Point(0, 0)) - .curve(new a.Point(123, 123), new a.Point(-123, 456), new a.Point(456, -123)) - a.points.a = a.paths.test.shiftFractionAlong(0.5) - a.points.b = a.paths.test.reverse().shiftFractionAlong(0.5) - expect(a.points.a.dist(a.points.b)).to.below(0.05); -}); - -it("Should shift a fraction along a line", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.paths.line = new a.Path() - .move(new a.Point(0, 0)) - .line(new a.Point(0, 40)) - .line(new a.Point(100, 40)); - expect(round(a.paths.line.shiftFractionAlong(0.5).x)).to.equal(30); - expect(round(a.paths.line.shiftFractionAlong(0.5).y)).to.equal(40); -}); - -it("Should find the bounding box of a line", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let Path = pattern.parts.a.Path; - let Point = pattern.parts.a.Point; - - let line = new Path().move(new Point(3, 2)).line(new Point(10, 40)); - let box = line.bbox(); - expect(box.topLeft.x).to.equal(3); - expect(box.topLeft.y).to.equal(2); - expect(box.bottomRight.x).to.equal(10); - expect(box.bottomRight.y).to.equal(40); - - line = new Path().move(new Point(10, 40)).line(new Point(3, 2)); - box = line.bbox(); - expect(box.topLeft.x).to.equal(3); - expect(box.topLeft.y).to.equal(2); - expect(box.bottomRight.x).to.equal(10); - expect(box.bottomRight.y).to.equal(40); - - line = new Path().move(new Point(1, 40)).line(new Point(31, 2)); - box = line.bbox(); - expect(box.topLeft.x).to.equal(1); - expect(box.topLeft.y).to.equal(2); - expect(box.bottomRight.x).to.equal(31); - expect(box.bottomRight.y).to.equal(40); - - line = new Path().move(new Point(31, 2)).line(new Point(1, 40)); - box = line.bbox(); - expect(box.topLeft.x).to.equal(1); - expect(box.topLeft.y).to.equal(2); - expect(box.bottomRight.x).to.equal(31); - expect(box.bottomRight.y).to.equal(40); - - line = new Path().move(new Point(11, 2)).line(new Point(11, 40)); - box = line.bbox(); - expect(box.topLeft.x).to.equal(11); - expect(box.topLeft.y).to.equal(2); - expect(box.bottomRight.x).to.equal(11); - expect(box.bottomRight.y).to.equal(40); - - line = new Path().move(new Point(11, 40)).line(new Point(11, 2)); - box = line.bbox(); - expect(box.topLeft.x).to.equal(11); - expect(box.topLeft.y).to.equal(2); - expect(box.bottomRight.x).to.equal(11); - expect(box.bottomRight.y).to.equal(40); - - line = new Path().move(new Point(11, 12)).line(new Point(41, 12)); - box = line.bbox(); - expect(box.topLeft.x).to.equal(11); - expect(box.topLeft.y).to.equal(12); - expect(box.bottomRight.x).to.equal(41); - expect(box.bottomRight.y).to.equal(12); - - line = new Path().move(new Point(41, 12)).line(new Point(11, 12)); - box = line.bbox(); - expect(box.topLeft.x).to.equal(11); - expect(box.topLeft.y).to.equal(12); - expect(box.bottomRight.x).to.equal(41); - expect(box.bottomRight.y).to.equal(12); -}); - -it("Should find the bounding box of a line", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.paths.curve = new a.Path() - .move(new a.Point(123, 456)) - .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)) - .close(); - let box = a.paths.curve.bbox(); - expect(round(box.topLeft.x)).to.equal(71.64); - expect(box.topLeft.y).to.equal(4); - expect(box.bottomRight.x).to.equal(230); - expect(box.bottomRight.y).to.equal(456); -}); - -it("Should reverse a path", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - let test = new a.Path() - .move(new a.Point(123, 456)) - .line(new a.Point(12, 23)) - .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)) - .close(); - let rev = test.reverse(); - let tb = test.bbox(); - let rb = rev.bbox(); - expect(tb.topLeft.x).to.equal(rb.topLeft.x); - expect(tb.topLeft.y).to.equal(rb.topLeft.y); - expect(tb.bottomRight.x).to.equal(rb.bottomRight.x); - expect(tb.bottomRight.y).to.equal(rb.bottomRight.y); - expect(rev.ops[1].type).to.equal("curve"); - expect(rev.ops[2].type).to.equal("line"); -}); - -it("Should find the edges of a path", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(45, 60); - a.points.B = new a.Point(10, 30); - a.points.BCp2 = new a.Point(40, 20); - a.points.C = new a.Point(90, 30); - a.points.CCp1 = new a.Point(50, -30); - a.points.D = new a.Point(-60, 90); - a.points.E = new a.Point(90, 190); - a.paths.test = new a.Path() - .move(a.points.A) - .line(a.points.B) - .curve(a.points.BCp2, a.points.CCp1, a.points.C) - .curve(a.points.E, a.points.D, a.points.A) - .close(); - expect(round(a.paths.test.edge("topLeft").x)).to.equal(7.7); - expect(round(a.paths.test.edge("topLeft").y)).to.equal(0.97); - expect(round(a.paths.test.edge("bottomLeft").x)).to.equal(7.7); - expect(round(a.paths.test.edge("bottomLeft").y)).to.equal(118.46); - expect(round(a.paths.test.edge("bottomRight").x)).to.equal(90); - expect(round(a.paths.test.edge("bottomRight").y)).to.equal(118.46); - expect(round(a.paths.test.edge("topRight").x)).to.equal(90); - expect(round(a.paths.test.edge("topRight").y)).to.equal(0.97); - expect(round(a.paths.test.edge("left").x)).to.equal(7.7); - expect(round(a.paths.test.edge("left").y)).to.equal(91.8); - expect(round(a.paths.test.edge("bottom").x)).to.equal(40.63); - expect(round(a.paths.test.edge("bottom").y)).to.equal(118.46); - expect(round(a.paths.test.edge("right").x)).to.equal(89.76); - expect(round(a.paths.test.edge("right").y)).to.equal(29.64); - expect(round(a.paths.test.edge("top").x)).to.equal(55.98); - expect(round(a.paths.test.edge("top").y)).to.equal(0.97); -}); - -it("Should find the edges of a path for corner cases", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(-45, -60); - a.points.B = new a.Point(45, 60); - a.points.C = new a.Point(-90, -160); - a.paths.test = new a.Path().move(a.points.A).line(a.points.B); - expect(round(a.paths.test.edge("top").x)).to.equal(-45); - expect(round(a.paths.test.edge("top").y)).to.equal(-60); - expect(round(a.paths.test.edge("left").x)).to.equal(-45); - expect(round(a.paths.test.edge("left").y)).to.equal(-60); - expect(round(a.paths.test.edge("bottom").x)).to.equal(45); - expect(round(a.paths.test.edge("bottom").y)).to.equal(60); - expect(round(a.paths.test.edge("right").x)).to.equal(45); - expect(round(a.paths.test.edge("right").y)).to.equal(60); - a.paths.test = new a.Path().move(a.points.B).line(a.points.A); - expect(round(a.paths.test.edge("top").x)).to.equal(-45); - expect(round(a.paths.test.edge("top").y)).to.equal(-60); - expect(round(a.paths.test.edge("left").x)).to.equal(-45); - expect(round(a.paths.test.edge("left").y)).to.equal(-60); - expect(round(a.paths.test.edge("bottom").x)).to.equal(45); - expect(round(a.paths.test.edge("bottom").y)).to.equal(60); - expect(round(a.paths.test.edge("right").x)).to.equal(45); - expect(round(a.paths.test.edge("right").y)).to.equal(60); -}); - -it("Should find the edge of a path for this edge-case", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(-109.7, 77, 12); - a.points.B = new a.Point(-27.33, 99.19); - a.points.C = new a.Point(-39.45, 137.4); - a.points.D = new a.Point(-61.52, 219.77); - a.paths.test = new a.Path() - .move(a.points.A) - .curve(a.points.B, a.points.C, a.points.D); - expect(round(a.paths.test.edge("right").x)).to.equal(-45.22); - expect(round(a.paths.test.edge("right").y)).to.equal(139.4); -}); - -it("Should find where a path intersects with an X value", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(95, 50); - a.points.B = new a.Point(10, 30); - a.points.BCp2 = new a.Point(40, 20); - a.points.C = new a.Point(90, 30); - a.points.CCp1 = new a.Point(50, -30); - a.points.D = new a.Point(50, 130); - a.points.DCp1 = new a.Point(150, 30); - a.paths.test = new a.Path() - .move(a.points.A) - .line(a.points.B) - .curve(a.points.BCp2, a.points.CCp1, a.points.C) - .curve(a.points.DCp1, a.points.DCp1, a.points.D) - .close(); - let intersections = a.paths.test.intersectsX(60); - expect(intersections.length).to.equal(4); - expect(round(intersections[0].x)).to.equal(60); - expect(round(intersections[0].y)).to.equal(41.76); - expect(round(intersections[1].x)).to.equal(60); - expect(round(intersections[1].y)).to.equal(1.45); - expect(round(intersections[2].x)).to.equal(60); - expect(round(intersections[2].y)).to.equal(120); - expect(round(intersections[3].x)).to.equal(60); - expect(round(intersections[3].y)).to.equal(112.22); -}); - -it("Should find where a path intersects with an Y value", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(95, 50); - a.points.B = new a.Point(10, 30); - a.points.BCp2 = new a.Point(40, 20); - a.points.C = new a.Point(90, 30); - a.points.CCp1 = new a.Point(50, -30); - a.points.D = new a.Point(50, 130); - a.points.DCp1 = new a.Point(150, 30); - a.paths.test = new a.Path() - .move(a.points.A) - .line(a.points.B) - .curve(a.points.BCp2, a.points.CCp1, a.points.C) - .curve(a.points.DCp1, a.points.DCp1, a.points.D) - .close(); - let intersections = a.paths.test.intersectsY(60); - expect(intersections.length).to.equal(2); - expect(round(intersections[0].x)).to.equal(117.83); - expect(round(intersections[0].y)).to.equal(60); - expect(round(intersections[1].x)).to.equal(89.38); - expect(round(intersections[1].y)).to.equal(60); -}); - -it("Should throw an error when not passing a value to path.intersectsX", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.paths.test = new a.Path(); - expect(() => a.paths.test.intersectsX()).to.throw(); - expect(() => a.paths.test.intersectsY()).to.throw(); -}); - -it("Should find the intersections between two paths", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(45, 60); - a.points.B = new a.Point(10, 30); - a.points.BCp2 = new a.Point(40, 20); - a.points.C = new a.Point(90, 30); - a.points.CCp1 = new a.Point(50, -30); - a.points.D = new a.Point(50, 130); - a.points.DCp1 = new a.Point(150, 30); - - a.points._A = new a.Point(55, 40); - a.points._B = new a.Point(0, 55); - a.points._BCp2 = new a.Point(40, -20); - a.points._C = new a.Point(90, 40); - a.points._CCp1 = new a.Point(50, -30); - a.points._D = new a.Point(40, 120); - a.points._DCp1 = new a.Point(180, 40); - - a.paths.example1 = new a.Path() - .move(a.points.A) - .line(a.points.B) - .curve(a.points.BCp2, a.points.CCp1, a.points.C) - .curve(a.points.DCp1, a.points.DCp1, a.points.D); - a.paths.example2 = new a.Path() - .move(a.points._A) - .line(a.points._B) - .curve(a.points._BCp2, a.points._CCp1, a.points._C) - .curve(a.points._DCp1, a.points._DCp1, a.points._D); - let intersections = a.paths.example1.intersects(a.paths.example2); - expect(intersections.length).to.equal(6); - expect(round(intersections[0].x)).to.equal(29.71); - expect(round(intersections[0].y)).to.equal(46.9); - expect(round(intersections[1].x)).to.equal(12.48); - expect(round(intersections[1].y)).to.equal(32.12); - expect(round(intersections[2].x)).to.equal(14.84); - expect(round(intersections[2].y)).to.equal(27.98); - expect(round(intersections[3].x)).to.equal(66.33); - expect(round(intersections[3].y)).to.equal(4.1); - expect(round(intersections[4].x)).to.equal(130.65); - expect(round(intersections[4].y)).to.equal(40.52); - expect(round(intersections[5].x)).to.equal(86.52); - expect(round(intersections[5].y)).to.equal(93.31); -}); - -it("Should throw an error when running path.intersect on an identical path", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.paths.test = new a.Path(); - expect(() => a.paths.test.intersects(a.paths.test)).to.throw(); -}); - -it("Should divide a path", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(45, 60); - a.points.B = new a.Point(10, 30); - a.points.BCp2 = new a.Point(40, 20); - a.points.C = new a.Point(90, 30); - a.points.CCp1 = new a.Point(50, -30); - a.points.D = new a.Point(-60, 90); - a.points.E = new a.Point(90, 190); - a.paths.test = new a.Path() - .move(a.points.A) - .line(a.points.B) - .curve(a.points.BCp2, a.points.CCp1, a.points.C) - .curve(a.points.E, a.points.D, a.points.A) - .close(); - let divided = a.paths.test.divide(); - expect(divided.length).to.equal(4); - expect(divided[0].ops[0].type).to.equal("move"); - expect(divided[0].ops[0].to.x).to.equal(45); - expect(divided[0].ops[0].to.y).to.equal(60); - expect(divided[0].ops[1].type).to.equal("line"); - expect(divided[0].ops[1].to.x).to.equal(10); - expect(divided[0].ops[1].to.y).to.equal(30); - expect(divided[1].ops[0].type).to.equal("move"); - expect(divided[1].ops[0].to.x).to.equal(10); - expect(divided[1].ops[0].to.y).to.equal(30); - expect(divided[1].ops[1].type).to.equal("curve"); - expect(divided[1].ops[1].cp1.x).to.equal(40); - expect(divided[1].ops[1].cp1.y).to.equal(20); - expect(divided[1].ops[1].cp2.x).to.equal(50); - expect(divided[1].ops[1].cp2.y).to.equal(-30); - expect(divided[1].ops[1].to.x).to.equal(90); - expect(divided[1].ops[1].to.y).to.equal(30); - expect(divided[2].ops[0].type).to.equal("move"); - expect(divided[2].ops[0].to.x).to.equal(90); - expect(divided[2].ops[0].to.y).to.equal(30); - expect(divided[2].ops[1].type).to.equal("curve"); - expect(divided[2].ops[1].cp1.x).to.equal(90); - expect(divided[2].ops[1].cp1.y).to.equal(190); - expect(divided[2].ops[1].cp2.x).to.equal(-60); - expect(divided[2].ops[1].cp2.y).to.equal(90); - expect(divided[2].ops[1].to.x).to.equal(45); - expect(divided[2].ops[1].to.y).to.equal(60); - expect(divided[3].ops[0].type).to.equal("move"); - expect(divided[3].ops[0].to.x).to.equal(45); - expect(divided[3].ops[0].to.y).to.equal(60); - expect(divided[3].ops[1].type).to.equal("line"); - expect(divided[3].ops[1].to.x).to.equal(45); - expect(divided[3].ops[1].to.y).to.equal(60); -}); - -it("Should split a path on a curve", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(45, 60); - a.points.B = new a.Point(10, 30); - a.points.BCp2 = new a.Point(40, 20); - a.points.C = new a.Point(90, 30); - a.points.CCp1 = new a.Point(50, -30); - a.points.D = new a.Point(50, 130); - a.points.DCp1 = new a.Point(150, 30); - - a.paths.test = new a.Path() - .move(a.points.A) - .line(a.points.B) - .curve(a.points.BCp2, a.points.CCp1, a.points.C) - .curve(a.points.DCp1, a.points.DCp1, a.points.D); - - a.points.split = a.paths.test.shiftAlong(120); - let halves = a.paths.test.split(a.points.split); - let curve = halves[0].ops.pop(); - expect(curve.type).to.equal("curve"); - expect(round(curve.cp1.x)).to.equal(35.08); - expect(round(curve.cp1.y)).to.equal(21.64); - expect(round(curve.cp2.x)).to.equal(46.19); - expect(round(curve.cp2.y)).to.equal(-14.69); - expect(round(curve.to.x)).to.equal(72.53); - expect(round(curve.to.y)).to.equal(8.71); -}); - -it("Should split a path on a line", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(45, 60); - a.points.B = new a.Point(10, 30); - a.points.BCp2 = new a.Point(40, 20); - a.points.C = new a.Point(90, 30); - a.points.CCp1 = new a.Point(50, -30); - a.points.D = new a.Point(50, 130); - a.points.DCp1 = new a.Point(150, 30); - - a.paths.test = new a.Path() - .move(a.points.A) - .line(a.points.B) - .curve(a.points.BCp2, a.points.CCp1, a.points.C) - .curve(a.points.DCp1, a.points.DCp1, a.points.D); - - a.points.split = a.paths.test.shiftAlong(20); - let halves = a.paths.test.split(a.points.split); - let line = halves[0].ops.pop(); - expect(line.type).to.equal("line"); - expect(round(line.to.x)).to.equal(29.81); - expect(round(line.to.y)).to.equal(46.98); -}); - -it("Should trim a path when lines overlap", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(0, 0); - a.points.B = new a.Point(100, 100); - a.points.C = new a.Point(0, 100); - a.points.D = new a.Point(100, 0); - - let test = new a.Path() - .move(new a.Point(0, 20)) - .line(a.points.A) - .line(a.points.B) - .line(a.points.C) - .line(a.points.D) - .line(a.points.A) - .trim(); - - expect(test.ops.length).to.equal(5); - expect(test.ops[2].to.x).to.equal(50); - expect(test.ops[2].to.y).to.equal(50); -}); - -it("Should trim a path when a line overlaps with a curve", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(0, 0); - a.points.B = new a.Point(100, 100); - a.points.C = new a.Point(0, 100); - a.points.D = new a.Point(100, 0); - - let test = new a.Path() - .move(new a.Point(0, 20)) - .line(a.points.A) - .curve(a.points.D, a.points.B, a.points.B) - .line(a.points.C) - .line(a.points.D) - .line(a.points.A) - .trim(); - - expect(test.ops.length).to.equal(5); - expect(round(test.ops[2].to.x)).to.equal(72.19); - expect(round(test.ops[2].to.y)).to.equal(27.81); -}); - -it("Should trim a path when a curves overlap", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(0, 0); - a.points.B = new a.Point(100, 100); - a.points.C = new a.Point(0, 100); - a.points.D = new a.Point(100, 0); - - let test = new a.Path() - .move(new a.Point(0, 20)) - .line(a.points.A) - .curve(a.points.D, a.points.B, a.points.B) - .line(a.points.C) - .curve(a.points.C, a.points.A, a.points.D) - .line(a.points.A) - .trim(); - - expect(test.ops.length).to.equal(5); - expect(round(test.ops[2].to.x)).to.equal(50); - expect(round(test.ops[2].to.y)).to.equal(11.01); -}); - -it("Should translate a path", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - a.points.A = new a.Point(0, 0); - a.points.B = new a.Point(100, 100); - a.points.C = new a.Point(0, 100); - a.points.D = new a.Point(100, 0); - - let base = new a.Path() - .move(a.points.A) - .curve(a.points.B, a.points.C, a.points.D); - let test = base.translate(10, 20); - - expect(test.ops.length).to.equal(2); - expect(test.ops[0].to.x).to.equal(10); - expect(test.ops[0].to.y).to.equal(20); - expect(test.ops[1].to.x).to.equal(110); - expect(test.ops[1].to.y).to.equal(20); -}); - -it("Should add a path attribute", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.line = new a.Path() - .move(new a.Point(0, 0)) - .line(new a.Point(0, 40)) - .attr("class", "foo") - .attr("class", "bar"); - expect(a.paths.line.attributes.get("class")).to.equal("foo bar"); -}); - -it("Should overwrite a path attribute", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - // Paths from shorthand have the raise method - const { Path } = a.shorthand() - a.paths.line = new Path() - .move(new a.Point(0, 0)) - .line(new a.Point(0, 40)) - .attr("class", "foo") - .attr("class", "bar") - .attr("class", "overwritten", true); - expect(a.paths.line.attributes.get("class")).to.equal("overwritten"); -}); - -it("Should move along a path even if it lands just on a joint", () => { - let pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - let a = pattern.parts.a; - - a.paths.curve = new a.Path() - .move(new a.Point(20.979322245694167, -219.8547313525503)) - ._curve( - new a.Point(35.33122482627704, -153.54225517257478), - new a.Point(61.99376179214562, -105.99242252587702) - ) - .curve( - new a.Point(88.85254026593002, -58.092613773317105), - new a.Point(136.13264764576948, -11.692646171119936), - new a.Point(170.69593749999996, -4.180844669736632e-14) - ) - a.points.test = a.paths.curve.shiftAlong(121.36690836797631) - expect(a.points.test).to.be.instanceOf(a.Point) -}) - -it("Should add raise methods to a path", () => { - const raise = () => 'hello' - const p1 = new freesewing.Path(10, 20).withRaise(raise); - expect(p1.raise()).to.equal('hello'); -}); - -it("Should add raise methods to a path", () => { - const raise = () => 'hello' - const p1 = new freesewing.Path().withRaise(raise); - expect(p1.raise()).to.equal('hello'); -}); - -it("Should set render to true/false", () => { - const p1 = new freesewing.Path().setRender(false) - expect(p1.render).to.equal(false); -}); - -it("Should set class with setClass", () => { - const p1 = new freesewing.Path().setClass('fabric') - p1.setClass() - expect(p1.attributes.get('class')).to.equal('fabric'); -}); - -it("Should raise a warning when moving to a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new freesewing.Path().withRaise(raise) - expect(invalid).to.equal(false); - try { - p1.move('a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when drawing a line to a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new freesewing.Path().withRaise(raise) - expect(invalid).to.equal(false); - try { - p1.line('a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when drawing a curve to a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new freesewing.Path().withRaise(raise) - const a = new freesewing.Point(0,0) - const b = new freesewing.Point(10,10) - expect(invalid).to.equal(false); - try { - p1.move(b).curve(a, b, 'c') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when drawing a curve with a Cp1 that is a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new freesewing.Path().withRaise(raise) - const a = new freesewing.Point(0,0) - const b = new freesewing.Point(10,10) - expect(invalid).to.equal(false); - try { - p1.move(b).curve(a, 'x', b) - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when drawing a curve with a Cp1 that is a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new freesewing.Path().withRaise(raise) - const b = new freesewing.Point(10,10) - expect(invalid).to.equal(false); - try { - p1.move(b).curve('a', b, b) - } - catch (err) { - expect(''+err).to.contain("copy is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when drawing a curve with a Cp2 that is a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new freesewing.Path().withRaise(raise) - const b = new freesewing.Point(10,10) - expect(invalid).to.equal(false); - try { - p1.move(b).curve(b, 'a', b) - } - catch (err) { - expect(''+err).to.contain("copy is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when drawing a _curve with a To that is a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new freesewing.Path().withRaise(raise) - const b = new freesewing.Point(10,10) - expect(invalid).to.equal(false); - try { - p1.move(b)._curve(b, 'a') - } - catch (err) { - expect(''+err).to.contain("copy is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when drawing a _curve with a Cp2 that is a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new freesewing.Path().withRaise(raise) - const b = new freesewing.Point(10,10) - expect(invalid).to.equal(false); - try { - p1.move(b)._curve('a', b) - } - catch (err) { - expect(''+err).to.contain("copy is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when drawing a curve_ with a To that is a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new freesewing.Path().withRaise(raise) - const b = new freesewing.Point(10,10) - expect(invalid).to.equal(false); - try { - p1.move(b).curve_(b, 'a') - } - catch (err) { - expect(''+err).to.contain("copy is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when drawing a curve_ with a Cp2 that is a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new freesewing.Path().withRaise(raise) - const b = new freesewing.Point(10,10) - expect(invalid).to.equal(false); - try { - p1.move(b).curve_('a', b) - } - catch (err) { - expect(''+err).to.contain("copy is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should add a noop operation", () => { - const p1 = new freesewing.Path().noop() - expect(p1.ops.length).to.equal(1); - expect(p1.ops[0].type).to.equal('noop'); -}); - -it("Should handle an insop operation", () => { - const a = new freesewing.Point(0,0) - const b = new freesewing.Point(10,10) - const p1 = new freesewing.Path().move(a).line(b) - const p2 = new freesewing.Path().noop('test').insop('test', p1) - expect(p2.ops.length).to.equal(2); - expect(p1.ops[0].type).to.equal('move'); - expect(p1.ops[1].type).to.equal('line'); -}); - -it("Should raise a warning when an insop operation used an falsy ID", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const a = new freesewing.Point(0,0) - const b = new freesewing.Point(10,10) - const p1 = new freesewing.Path().move(a).line(b) - expect(invalid).to.equal(false); - const p2 = new freesewing.Path().withRaise(raise).noop('test').insop(false, p1) - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when an insop operation used an falsy ID", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const a = new freesewing.Point(0,0) - const b = new freesewing.Point(10,10) - const p1 = new freesewing.Path().move(a).line(b) - expect(invalid).to.equal(false); - try { - new freesewing.Path().withRaise(raise).noop('test').insop('test') - } - catch (err) { - expect(''+err).to.contain("Cannot read properties of undefined (reading 'ops')") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when setting an attribute without a name", () => { - let invalid = false - const raise = { warning: () => invalid = true } - expect(invalid).to.equal(false); - const p1 = new freesewing.Path().withRaise(raise).attr() - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when setting an attribute without a value", () => { - let invalid = false - const raise = { warning: () => invalid = true } - expect(invalid).to.equal(false); - const p1 = new freesewing.Path().withRaise(raise).attr('test') - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when calling offset without a distance", () => { - const pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - const { Path, Point, points, paths } = pattern.parts.a.shorthand() - points.a = new Point(0,0) - points.b = new Point(10,10) - paths.a = new Path().move(points.a).line(points.b) - paths.b = paths.a.offset() - expect(pattern.events.error.length).to.equal(1) - expect(pattern.events.error[0]).to.equal("Called `Path.offset(distance)` but `distance` is not a number") -}); - -it("Should raise a warning when calling join without a path", () => { - const pattern = new freesewing.Pattern(); - pattern.parts.a = new pattern.Part(); - const { Path, Point, points, paths } = pattern.parts.a.shorthand() - points.a = new Point(0,0) - points.b = new Point(10,10) - try { - //paths.a = new Path().move(points.a).line(points.b).join() - pattern.parts.a.paths.a = new Path().move(points.a).line(points.b).join() - } - catch (err) { - expect(''+err).to.contain("Cannot read properties of undefined (reading 'ops')") - } - expect(pattern.events.error.length).to.equal(1) - expect(pattern.events.error[0]).to.equal("Called `Path.join(that)` but `that` is not a `Path` object") -}); - -it("Should raise a warning when calling start on a path without drawing operations", () => { - let invalid = false - const raise = { error: () => invalid = true } - expect(invalid).to.equal(false); - try { - new freesewing.Path().withRaise(raise).start() - } - catch (err) { - expect(''+err).to.contain("Cannot read properties of undefined (reading 'to')") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when calling end on a path without drawing operations", () => { - let invalid = false - const raise = { error: () => invalid = true } - expect(invalid).to.equal(false); - try { - new freesewing.Path().withRaise(raise).end() - } - catch (err) { - expect(''+err).to.contain("Cannot read properties of undefined (reading 'type')") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when calling shiftAlong but distance is not a number", () => { - let invalid = false - const raise = { error: () => invalid = true } - expect(invalid).to.equal(false); - new freesewing.Path() - .withRaise(raise) - .move(new freesewing.Point(0,0)) - .line(new freesewing.Point(10,10)) - .shiftAlong() - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when calling shiftFractionalong but fraction is not a number", () => { - let invalid = false - const raise = { - error: () => invalid = true, - warning: () => invalid = true, - } - expect(invalid).to.equal(false); - new freesewing.Path() - .withRaise(raise) - .move(new freesewing.Point(0,0).withRaise(raise)) - .line(new freesewing.Point(10,10).withRaise(raise)) - .line(new freesewing.Point(10,20).withRaise(raise)) - .shiftFractionAlong() - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when splitting a path on a non-point", () => { - let invalid = false - const raise = { - error: () => invalid = true, - warning: () => invalid = true, - } - const from = new freesewing.Point(0,0).withRaise(raise) - const cp1 = new freesewing.Point(10,0).withRaise(raise) - const cp2 = new freesewing.Point(90,0).withRaise(raise) - const to = new freesewing.Point(100,0).withRaise(raise) - const path = new freesewing.Path() - .withRaise(raise) - .move(from) - .curve(cp1, cp2, to) - .line(from) - .line(cp1) - try { - path.split() - } - catch (err) { - expect(''+err).to.contain("Cannot read properties of undefined (reading 'check')") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when splitting a path on a non-point", () => { - let invalid = false - const raise = { - error: () => invalid = true, - warning: () => invalid = true, - } - const from = new freesewing.Point(0,0).withRaise(raise) - const cp1 = new freesewing.Point(10,0).withRaise(raise) - const cp2 = new freesewing.Point(90,0).withRaise(raise) - const to = new freesewing.Point(100,0).withRaise(raise) - const path = new freesewing.Path() - .withRaise(raise) - .move(from) - .curve(cp1, cp2, to) - .line(from) - try { - path.split() - } - catch (err) { - expect(''+err).to.contain("Cannot read properties of undefined (reading 'check')") - } - expect(invalid).to.equal(true); +describe('Path', () => { + it("Should offset a line", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)); + a.paths.offset = a.paths.line.offset(10); + pattern.render(); + expect(a.paths.offset.bottomRight.x).to.equal(-10); + expect(a.paths.offset.bottomRight.y).to.equal(40); + }); + + it("Should offset a curve", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.curve = new a.Path() + .move(new a.Point(0, 0)) + .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)); + a.paths.offset = a.paths.curve.offset(10); + pattern.render(); + expect(round(a.paths.offset.bottomRight.x)).to.equal(72.18); + expect(round(a.paths.offset.bottomRight.y)).to.equal(38.26); + }); + + it("Should offset a curve where cp1 = start", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.curve = new a.Path() + .move(new a.Point(0, 0)) + .curve(new a.Point(0, 0), new a.Point(123, 34), new a.Point(23, 4)); + a.paths.offset = a.paths.curve.offset(10); + pattern.render(); + expect(round(a.paths.offset.bottomRight.x)).to.equal(72.63); + expect(round(a.paths.offset.bottomRight.y)).to.equal(26.48); + }); + + it("Should offset a curve where cp2 = end", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.curve = new a.Path() + .move(new a.Point(0, 0)) + .curve(new a.Point(40, 0), new a.Point(123, 34), new a.Point(123, 34)) + .close(); + a.paths.offset = a.paths.curve.offset(10); + pattern.render(); + expect(round(a.paths.offset.bottomRight.x)).to.equal(119.26); + expect(round(a.paths.offset.bottomRight.y)).to.equal(43.27); + }); + + it("Should throw error when offsetting line that is no line", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.line = new a.Path().move(new a.Point(0, 40)).line(new a.Point(0, 40)); + expect(() => a.paths.line.offset(10)).to.throw(); + }); + + it("Should return the length of a line", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)); + expect(a.paths.line.length()).to.equal(40); + }); + + it("Should return the length of a curve", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.curve = new a.Path() + .move(new a.Point(0, 0)) + .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)) + .close(); + expect(round(a.paths.curve.length())).to.equal(145.11); + }); + + it("Should return the path start point", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.curve = new a.Path() + .move(new a.Point(123, 456)) + .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)) + .close(); + expect(a.paths.curve.start().x).to.equal(123); + expect(a.paths.curve.start().y).to.equal(456); + }); + + it("Should return the path end point", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.curve = new a.Path() + .move(new a.Point(123, 456)) + .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)); + expect(a.paths.curve.end().x).to.equal(23); + expect(a.paths.curve.end().y).to.equal(4); + a.paths.curve.close(); + expect(a.paths.curve.end().x).to.equal(123); + expect(a.paths.curve.end().y).to.equal(456); + }); + + it("Should calculate that path boundary", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.curve = new a.Path() + .move(new a.Point(123, 456)) + .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)); + a.paths.curve.boundary(); + expect(a.paths.curve.topLeft.x).to.equal(71.6413460920667); + expect(a.paths.curve.topLeft.y).to.equal(4); + a.paths.curve.boundary(); + expect(a.paths.curve.bottomRight.x).to.equal(230); + expect(a.paths.curve.bottomRight.y).to.equal(456); + }); + + it("Should clone a path", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.curve = new a.Path() + .move(new a.Point(123, 456)) + .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)); + let b = a.paths.curve.clone(); + b.boundary(); + expect(b.topLeft.x).to.equal(71.6413460920667); + expect(b.topLeft.y).to.equal(4); + b = b.clone(); + expect(b.bottomRight.x).to.equal(230); + expect(b.bottomRight.y).to.equal(456); + }); + + it("Should join paths", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)); + a.paths.curve = new a.Path() + .move(new a.Point(123, 456)) + .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)); + a.paths.joint = a.paths.curve.join(a.paths.line); + expect(a.paths.joint.ops.length).to.equal(4); + }); + + it("Should throw error when joining a closed paths", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)); + a.paths.curve = new a.Path() + .move(new a.Point(123, 456)) + .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)) + .close(); + expect(() => a.paths.curve.join(a.paths.line)).to.throw(); + }); + + it("Should shift along a line", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)); + expect(a.paths.line.shiftAlong(20).y).to.equal(20); + }); + + it("Should not shift along a path/line if we end up on the end point", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(10, 0)); + expect(a.paths.line.shiftAlong(10).x).to.equal(10); + }); + + it("Should shift along lines", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.line = new a.Path() + .move(new a.Point(0, 0)) + .line(new a.Point(0, 40)) + .line(new a.Point(100, 40)); + expect(a.paths.line.shiftAlong(50).x).to.equal(10); + expect(a.paths.line.shiftAlong(50).y).to.equal(40); + }); + + it("Should shift along curve + line", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.test = new a.Path() + .move(new a.Point(0, 0)) + .line(new a.Point(0, 40)) + .curve(new a.Point(40, 40), new a.Point(40, 0), new a.Point(200, 0)) + .line(new a.Point(200, 400)); + expect(round(a.paths.test.shiftAlong(500).x)).to.equal(200); + expect(round(a.paths.test.shiftAlong(500).y)).to.equal(253.74); + }); + + it("Should throw error when shifting along path further than it's long", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.paths.test = new a.Path() + .move(new a.Point(0, 0)) + .line(new a.Point(0, 40)) + .line(new a.Point(200, 400)); + expect(() => a.paths.test.shiftAlong(500)).to.throw(); + }); + + it("Should shift along with sufficient precision", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.paths.test = new a.Path() + .move(new a.Point(0, 0)) + .curve(new a.Point(123, 123), new a.Point(-123, 456), new a.Point(456, -123)) + a.points.a = a.paths.test.shiftAlong(100) + a.points.b = a.paths.test.reverse().shiftAlong(a.paths.test.length()-100) + expect(a.points.a.dist(a.points.b)).to.below(0.05); + }); + + it("Should shift fraction with sufficient precision", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.paths.test = new a.Path() + .move(new a.Point(0, 0)) + .curve(new a.Point(123, 123), new a.Point(-123, 456), new a.Point(456, -123)) + a.points.a = a.paths.test.shiftFractionAlong(0.5) + a.points.b = a.paths.test.reverse().shiftFractionAlong(0.5) + expect(a.points.a.dist(a.points.b)).to.below(0.05); + }); + + it("Should shift a fraction along a line", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.paths.line = new a.Path() + .move(new a.Point(0, 0)) + .line(new a.Point(0, 40)) + .line(new a.Point(100, 40)); + expect(round(a.paths.line.shiftFractionAlong(0.5).x)).to.equal(30); + expect(round(a.paths.line.shiftFractionAlong(0.5).y)).to.equal(40); + }); + + it("Should find the bounding box of a line", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let Path = pattern.parts.a.Path; + let Point = pattern.parts.a.Point; + + let line = new Path().move(new Point(3, 2)).line(new Point(10, 40)); + let box = line.bbox(); + expect(box.topLeft.x).to.equal(3); + expect(box.topLeft.y).to.equal(2); + expect(box.bottomRight.x).to.equal(10); + expect(box.bottomRight.y).to.equal(40); + + line = new Path().move(new Point(10, 40)).line(new Point(3, 2)); + box = line.bbox(); + expect(box.topLeft.x).to.equal(3); + expect(box.topLeft.y).to.equal(2); + expect(box.bottomRight.x).to.equal(10); + expect(box.bottomRight.y).to.equal(40); + + line = new Path().move(new Point(1, 40)).line(new Point(31, 2)); + box = line.bbox(); + expect(box.topLeft.x).to.equal(1); + expect(box.topLeft.y).to.equal(2); + expect(box.bottomRight.x).to.equal(31); + expect(box.bottomRight.y).to.equal(40); + + line = new Path().move(new Point(31, 2)).line(new Point(1, 40)); + box = line.bbox(); + expect(box.topLeft.x).to.equal(1); + expect(box.topLeft.y).to.equal(2); + expect(box.bottomRight.x).to.equal(31); + expect(box.bottomRight.y).to.equal(40); + + line = new Path().move(new Point(11, 2)).line(new Point(11, 40)); + box = line.bbox(); + expect(box.topLeft.x).to.equal(11); + expect(box.topLeft.y).to.equal(2); + expect(box.bottomRight.x).to.equal(11); + expect(box.bottomRight.y).to.equal(40); + + line = new Path().move(new Point(11, 40)).line(new Point(11, 2)); + box = line.bbox(); + expect(box.topLeft.x).to.equal(11); + expect(box.topLeft.y).to.equal(2); + expect(box.bottomRight.x).to.equal(11); + expect(box.bottomRight.y).to.equal(40); + + line = new Path().move(new Point(11, 12)).line(new Point(41, 12)); + box = line.bbox(); + expect(box.topLeft.x).to.equal(11); + expect(box.topLeft.y).to.equal(12); + expect(box.bottomRight.x).to.equal(41); + expect(box.bottomRight.y).to.equal(12); + + line = new Path().move(new Point(41, 12)).line(new Point(11, 12)); + box = line.bbox(); + expect(box.topLeft.x).to.equal(11); + expect(box.topLeft.y).to.equal(12); + expect(box.bottomRight.x).to.equal(41); + expect(box.bottomRight.y).to.equal(12); + }); + + it("Should find the bounding box of a line", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.paths.curve = new a.Path() + .move(new a.Point(123, 456)) + .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)) + .close(); + let box = a.paths.curve.bbox(); + expect(round(box.topLeft.x)).to.equal(71.64); + expect(box.topLeft.y).to.equal(4); + expect(box.bottomRight.x).to.equal(230); + expect(box.bottomRight.y).to.equal(456); + }); + + it("Should reverse a path", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + let test = new a.Path() + .move(new a.Point(123, 456)) + .line(new a.Point(12, 23)) + .curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(230, 4)) + .close(); + let rev = test.reverse(); + let tb = test.bbox(); + let rb = rev.bbox(); + expect(tb.topLeft.x).to.equal(rb.topLeft.x); + expect(tb.topLeft.y).to.equal(rb.topLeft.y); + expect(tb.bottomRight.x).to.equal(rb.bottomRight.x); + expect(tb.bottomRight.y).to.equal(rb.bottomRight.y); + expect(rev.ops[1].type).to.equal("curve"); + expect(rev.ops[2].type).to.equal("line"); + }); + + it("Should find the edges of a path", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(45, 60); + a.points.B = new a.Point(10, 30); + a.points.BCp2 = new a.Point(40, 20); + a.points.C = new a.Point(90, 30); + a.points.CCp1 = new a.Point(50, -30); + a.points.D = new a.Point(-60, 90); + a.points.E = new a.Point(90, 190); + a.paths.test = new a.Path() + .move(a.points.A) + .line(a.points.B) + .curve(a.points.BCp2, a.points.CCp1, a.points.C) + .curve(a.points.E, a.points.D, a.points.A) + .close(); + expect(round(a.paths.test.edge("topLeft").x)).to.equal(7.7); + expect(round(a.paths.test.edge("topLeft").y)).to.equal(0.97); + expect(round(a.paths.test.edge("bottomLeft").x)).to.equal(7.7); + expect(round(a.paths.test.edge("bottomLeft").y)).to.equal(118.46); + expect(round(a.paths.test.edge("bottomRight").x)).to.equal(90); + expect(round(a.paths.test.edge("bottomRight").y)).to.equal(118.46); + expect(round(a.paths.test.edge("topRight").x)).to.equal(90); + expect(round(a.paths.test.edge("topRight").y)).to.equal(0.97); + expect(round(a.paths.test.edge("left").x)).to.equal(7.7); + expect(round(a.paths.test.edge("left").y)).to.equal(91.8); + expect(round(a.paths.test.edge("bottom").x)).to.equal(40.63); + expect(round(a.paths.test.edge("bottom").y)).to.equal(118.46); + expect(round(a.paths.test.edge("right").x)).to.equal(89.76); + expect(round(a.paths.test.edge("right").y)).to.equal(29.64); + expect(round(a.paths.test.edge("top").x)).to.equal(55.98); + expect(round(a.paths.test.edge("top").y)).to.equal(0.97); + }); + + it("Should find the edges of a path for corner cases", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(-45, -60); + a.points.B = new a.Point(45, 60); + a.points.C = new a.Point(-90, -160); + a.paths.test = new a.Path().move(a.points.A).line(a.points.B); + expect(round(a.paths.test.edge("top").x)).to.equal(-45); + expect(round(a.paths.test.edge("top").y)).to.equal(-60); + expect(round(a.paths.test.edge("left").x)).to.equal(-45); + expect(round(a.paths.test.edge("left").y)).to.equal(-60); + expect(round(a.paths.test.edge("bottom").x)).to.equal(45); + expect(round(a.paths.test.edge("bottom").y)).to.equal(60); + expect(round(a.paths.test.edge("right").x)).to.equal(45); + expect(round(a.paths.test.edge("right").y)).to.equal(60); + a.paths.test = new a.Path().move(a.points.B).line(a.points.A); + expect(round(a.paths.test.edge("top").x)).to.equal(-45); + expect(round(a.paths.test.edge("top").y)).to.equal(-60); + expect(round(a.paths.test.edge("left").x)).to.equal(-45); + expect(round(a.paths.test.edge("left").y)).to.equal(-60); + expect(round(a.paths.test.edge("bottom").x)).to.equal(45); + expect(round(a.paths.test.edge("bottom").y)).to.equal(60); + expect(round(a.paths.test.edge("right").x)).to.equal(45); + expect(round(a.paths.test.edge("right").y)).to.equal(60); + }); + + it("Should find the edge of a path for this edge-case", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(-109.7, 77, 12); + a.points.B = new a.Point(-27.33, 99.19); + a.points.C = new a.Point(-39.45, 137.4); + a.points.D = new a.Point(-61.52, 219.77); + a.paths.test = new a.Path() + .move(a.points.A) + .curve(a.points.B, a.points.C, a.points.D); + expect(round(a.paths.test.edge("right").x)).to.equal(-45.22); + expect(round(a.paths.test.edge("right").y)).to.equal(139.4); + }); + + it("Should find where a path intersects with an X value", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(95, 50); + a.points.B = new a.Point(10, 30); + a.points.BCp2 = new a.Point(40, 20); + a.points.C = new a.Point(90, 30); + a.points.CCp1 = new a.Point(50, -30); + a.points.D = new a.Point(50, 130); + a.points.DCp1 = new a.Point(150, 30); + a.paths.test = new a.Path() + .move(a.points.A) + .line(a.points.B) + .curve(a.points.BCp2, a.points.CCp1, a.points.C) + .curve(a.points.DCp1, a.points.DCp1, a.points.D) + .close(); + let intersections = a.paths.test.intersectsX(60); + expect(intersections.length).to.equal(4); + expect(round(intersections[0].x)).to.equal(60); + expect(round(intersections[0].y)).to.equal(41.76); + expect(round(intersections[1].x)).to.equal(60); + expect(round(intersections[1].y)).to.equal(1.45); + expect(round(intersections[2].x)).to.equal(60); + expect(round(intersections[2].y)).to.equal(120); + expect(round(intersections[3].x)).to.equal(60); + expect(round(intersections[3].y)).to.equal(112.22); + }); + + it("Should find where a path intersects with an Y value", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(95, 50); + a.points.B = new a.Point(10, 30); + a.points.BCp2 = new a.Point(40, 20); + a.points.C = new a.Point(90, 30); + a.points.CCp1 = new a.Point(50, -30); + a.points.D = new a.Point(50, 130); + a.points.DCp1 = new a.Point(150, 30); + a.paths.test = new a.Path() + .move(a.points.A) + .line(a.points.B) + .curve(a.points.BCp2, a.points.CCp1, a.points.C) + .curve(a.points.DCp1, a.points.DCp1, a.points.D) + .close(); + let intersections = a.paths.test.intersectsY(60); + expect(intersections.length).to.equal(2); + expect(round(intersections[0].x)).to.equal(117.83); + expect(round(intersections[0].y)).to.equal(60); + expect(round(intersections[1].x)).to.equal(89.38); + expect(round(intersections[1].y)).to.equal(60); + }); + + it("Should throw an error when not passing a value to path.intersectsX", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.paths.test = new a.Path(); + expect(() => a.paths.test.intersectsX()).to.throw(); + expect(() => a.paths.test.intersectsY()).to.throw(); + }); + + it("Should find the intersections between two paths", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(45, 60); + a.points.B = new a.Point(10, 30); + a.points.BCp2 = new a.Point(40, 20); + a.points.C = new a.Point(90, 30); + a.points.CCp1 = new a.Point(50, -30); + a.points.D = new a.Point(50, 130); + a.points.DCp1 = new a.Point(150, 30); + + a.points._A = new a.Point(55, 40); + a.points._B = new a.Point(0, 55); + a.points._BCp2 = new a.Point(40, -20); + a.points._C = new a.Point(90, 40); + a.points._CCp1 = new a.Point(50, -30); + a.points._D = new a.Point(40, 120); + a.points._DCp1 = new a.Point(180, 40); + + a.paths.example1 = new a.Path() + .move(a.points.A) + .line(a.points.B) + .curve(a.points.BCp2, a.points.CCp1, a.points.C) + .curve(a.points.DCp1, a.points.DCp1, a.points.D); + a.paths.example2 = new a.Path() + .move(a.points._A) + .line(a.points._B) + .curve(a.points._BCp2, a.points._CCp1, a.points._C) + .curve(a.points._DCp1, a.points._DCp1, a.points._D); + let intersections = a.paths.example1.intersects(a.paths.example2); + expect(intersections.length).to.equal(6); + expect(round(intersections[0].x)).to.equal(29.71); + expect(round(intersections[0].y)).to.equal(46.9); + expect(round(intersections[1].x)).to.equal(12.48); + expect(round(intersections[1].y)).to.equal(32.12); + expect(round(intersections[2].x)).to.equal(14.84); + expect(round(intersections[2].y)).to.equal(27.98); + expect(round(intersections[3].x)).to.equal(66.33); + expect(round(intersections[3].y)).to.equal(4.1); + expect(round(intersections[4].x)).to.equal(130.65); + expect(round(intersections[4].y)).to.equal(40.52); + expect(round(intersections[5].x)).to.equal(86.52); + expect(round(intersections[5].y)).to.equal(93.31); + }); + + it("Should throw an error when running path.intersect on an identical path", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.paths.test = new a.Path(); + expect(() => a.paths.test.intersects(a.paths.test)).to.throw(); + }); + + it("Should divide a path", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(45, 60); + a.points.B = new a.Point(10, 30); + a.points.BCp2 = new a.Point(40, 20); + a.points.C = new a.Point(90, 30); + a.points.CCp1 = new a.Point(50, -30); + a.points.D = new a.Point(-60, 90); + a.points.E = new a.Point(90, 190); + a.paths.test = new a.Path() + .move(a.points.A) + .line(a.points.B) + .curve(a.points.BCp2, a.points.CCp1, a.points.C) + .curve(a.points.E, a.points.D, a.points.A) + .close(); + let divided = a.paths.test.divide(); + expect(divided.length).to.equal(4); + expect(divided[0].ops[0].type).to.equal("move"); + expect(divided[0].ops[0].to.x).to.equal(45); + expect(divided[0].ops[0].to.y).to.equal(60); + expect(divided[0].ops[1].type).to.equal("line"); + expect(divided[0].ops[1].to.x).to.equal(10); + expect(divided[0].ops[1].to.y).to.equal(30); + expect(divided[1].ops[0].type).to.equal("move"); + expect(divided[1].ops[0].to.x).to.equal(10); + expect(divided[1].ops[0].to.y).to.equal(30); + expect(divided[1].ops[1].type).to.equal("curve"); + expect(divided[1].ops[1].cp1.x).to.equal(40); + expect(divided[1].ops[1].cp1.y).to.equal(20); + expect(divided[1].ops[1].cp2.x).to.equal(50); + expect(divided[1].ops[1].cp2.y).to.equal(-30); + expect(divided[1].ops[1].to.x).to.equal(90); + expect(divided[1].ops[1].to.y).to.equal(30); + expect(divided[2].ops[0].type).to.equal("move"); + expect(divided[2].ops[0].to.x).to.equal(90); + expect(divided[2].ops[0].to.y).to.equal(30); + expect(divided[2].ops[1].type).to.equal("curve"); + expect(divided[2].ops[1].cp1.x).to.equal(90); + expect(divided[2].ops[1].cp1.y).to.equal(190); + expect(divided[2].ops[1].cp2.x).to.equal(-60); + expect(divided[2].ops[1].cp2.y).to.equal(90); + expect(divided[2].ops[1].to.x).to.equal(45); + expect(divided[2].ops[1].to.y).to.equal(60); + expect(divided[3].ops[0].type).to.equal("move"); + expect(divided[3].ops[0].to.x).to.equal(45); + expect(divided[3].ops[0].to.y).to.equal(60); + expect(divided[3].ops[1].type).to.equal("line"); + expect(divided[3].ops[1].to.x).to.equal(45); + expect(divided[3].ops[1].to.y).to.equal(60); + }); + + it("Should split a path on a curve", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(45, 60); + a.points.B = new a.Point(10, 30); + a.points.BCp2 = new a.Point(40, 20); + a.points.C = new a.Point(90, 30); + a.points.CCp1 = new a.Point(50, -30); + a.points.D = new a.Point(50, 130); + a.points.DCp1 = new a.Point(150, 30); + + a.paths.test = new a.Path() + .move(a.points.A) + .line(a.points.B) + .curve(a.points.BCp2, a.points.CCp1, a.points.C) + .curve(a.points.DCp1, a.points.DCp1, a.points.D); + + a.points.split = a.paths.test.shiftAlong(120); + let halves = a.paths.test.split(a.points.split); + let curve = halves[0].ops.pop(); + expect(curve.type).to.equal("curve"); + expect(round(curve.cp1.x)).to.equal(35.08); + expect(round(curve.cp1.y)).to.equal(21.64); + expect(round(curve.cp2.x)).to.equal(46.19); + expect(round(curve.cp2.y)).to.equal(-14.69); + expect(round(curve.to.x)).to.equal(72.53); + expect(round(curve.to.y)).to.equal(8.71); + }); + + it("Should split a path on a line", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(45, 60); + a.points.B = new a.Point(10, 30); + a.points.BCp2 = new a.Point(40, 20); + a.points.C = new a.Point(90, 30); + a.points.CCp1 = new a.Point(50, -30); + a.points.D = new a.Point(50, 130); + a.points.DCp1 = new a.Point(150, 30); + + a.paths.test = new a.Path() + .move(a.points.A) + .line(a.points.B) + .curve(a.points.BCp2, a.points.CCp1, a.points.C) + .curve(a.points.DCp1, a.points.DCp1, a.points.D); + + a.points.split = a.paths.test.shiftAlong(20); + let halves = a.paths.test.split(a.points.split); + let line = halves[0].ops.pop(); + expect(line.type).to.equal("line"); + expect(round(line.to.x)).to.equal(29.81); + expect(round(line.to.y)).to.equal(46.98); + }); + + it("Should trim a path when lines overlap", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(0, 0); + a.points.B = new a.Point(100, 100); + a.points.C = new a.Point(0, 100); + a.points.D = new a.Point(100, 0); + + let test = new a.Path() + .move(new a.Point(0, 20)) + .line(a.points.A) + .line(a.points.B) + .line(a.points.C) + .line(a.points.D) + .line(a.points.A) + .trim(); + + expect(test.ops.length).to.equal(5); + expect(test.ops[2].to.x).to.equal(50); + expect(test.ops[2].to.y).to.equal(50); + }); + + it("Should trim a path when a line overlaps with a curve", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(0, 0); + a.points.B = new a.Point(100, 100); + a.points.C = new a.Point(0, 100); + a.points.D = new a.Point(100, 0); + + let test = new a.Path() + .move(new a.Point(0, 20)) + .line(a.points.A) + .curve(a.points.D, a.points.B, a.points.B) + .line(a.points.C) + .line(a.points.D) + .line(a.points.A) + .trim(); + + expect(test.ops.length).to.equal(5); + expect(round(test.ops[2].to.x)).to.equal(72.19); + expect(round(test.ops[2].to.y)).to.equal(27.81); + }); + + it("Should trim a path when a curves overlap", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(0, 0); + a.points.B = new a.Point(100, 100); + a.points.C = new a.Point(0, 100); + a.points.D = new a.Point(100, 0); + + let test = new a.Path() + .move(new a.Point(0, 20)) + .line(a.points.A) + .curve(a.points.D, a.points.B, a.points.B) + .line(a.points.C) + .curve(a.points.C, a.points.A, a.points.D) + .line(a.points.A) + .trim(); + + expect(test.ops.length).to.equal(5); + expect(round(test.ops[2].to.x)).to.equal(50); + expect(round(test.ops[2].to.y)).to.equal(11.01); + }); + + it("Should translate a path", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + a.points.A = new a.Point(0, 0); + a.points.B = new a.Point(100, 100); + a.points.C = new a.Point(0, 100); + a.points.D = new a.Point(100, 0); + + let base = new a.Path() + .move(a.points.A) + .curve(a.points.B, a.points.C, a.points.D); + let test = base.translate(10, 20); + + expect(test.ops.length).to.equal(2); + expect(test.ops[0].to.x).to.equal(10); + expect(test.ops[0].to.y).to.equal(20); + expect(test.ops[1].to.x).to.equal(110); + expect(test.ops[1].to.y).to.equal(20); + }); + + it("Should add a path attribute", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.line = new a.Path() + .move(new a.Point(0, 0)) + .line(new a.Point(0, 40)) + .attr("class", "foo") + .attr("class", "bar"); + expect(a.paths.line.attributes.get("class")).to.equal("foo bar"); + }); + + it("Should overwrite a path attribute", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + // Paths from shorthand have the raise method + const { Path } = a.shorthand() + a.paths.line = new Path() + .move(new a.Point(0, 0)) + .line(new a.Point(0, 40)) + .attr("class", "foo") + .attr("class", "bar") + .attr("class", "overwritten", true); + expect(a.paths.line.attributes.get("class")).to.equal("overwritten"); + }); + + it("Should move along a path even if it lands just on a joint", () => { + let pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + let a = pattern.parts.a; + + a.paths.curve = new a.Path() + .move(new a.Point(20.979322245694167, -219.8547313525503)) + ._curve( + new a.Point(35.33122482627704, -153.54225517257478), + new a.Point(61.99376179214562, -105.99242252587702) + ) + .curve( + new a.Point(88.85254026593002, -58.092613773317105), + new a.Point(136.13264764576948, -11.692646171119936), + new a.Point(170.69593749999996, -4.180844669736632e-14) + ) + a.points.test = a.paths.curve.shiftAlong(121.36690836797631) + expect(a.points.test).to.be.instanceOf(a.Point) + }) + + it("Should add raise methods to a path", () => { + const raise = () => 'hello' + const p1 = new freesewing.Path(10, 20).withRaise(raise); + expect(p1.raise()).to.equal('hello'); + }); + + it("Should add raise methods to a path", () => { + const raise = () => 'hello' + const p1 = new freesewing.Path().withRaise(raise); + expect(p1.raise()).to.equal('hello'); + }); + + it("Should set render to true/false", () => { + const p1 = new freesewing.Path().setRender(false) + expect(p1.render).to.equal(false); + }); + + it("Should set class with setClass", () => { + const p1 = new freesewing.Path().setClass('fabric') + p1.setClass() + expect(p1.attributes.get('class')).to.equal('fabric'); + }); + + it("Should raise a warning when moving to a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new freesewing.Path().withRaise(raise) + expect(invalid).to.equal(false); + try { + p1.move('a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when drawing a line to a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new freesewing.Path().withRaise(raise) + expect(invalid).to.equal(false); + try { + p1.line('a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when drawing a curve to a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new freesewing.Path().withRaise(raise) + const a = new freesewing.Point(0,0) + const b = new freesewing.Point(10,10) + expect(invalid).to.equal(false); + try { + p1.move(b).curve(a, b, 'c') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when drawing a curve with a Cp1 that is a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new freesewing.Path().withRaise(raise) + const a = new freesewing.Point(0,0) + const b = new freesewing.Point(10,10) + expect(invalid).to.equal(false); + try { + p1.move(b).curve(a, 'x', b) + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when drawing a curve with a Cp1 that is a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new freesewing.Path().withRaise(raise) + const b = new freesewing.Point(10,10) + expect(invalid).to.equal(false); + try { + p1.move(b).curve('a', b, b) + } + catch (err) { + expect(''+err).to.contain("copy is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when drawing a curve with a Cp2 that is a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new freesewing.Path().withRaise(raise) + const b = new freesewing.Point(10,10) + expect(invalid).to.equal(false); + try { + p1.move(b).curve(b, 'a', b) + } + catch (err) { + expect(''+err).to.contain("copy is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when drawing a _curve with a To that is a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new freesewing.Path().withRaise(raise) + const b = new freesewing.Point(10,10) + expect(invalid).to.equal(false); + try { + p1.move(b)._curve(b, 'a') + } + catch (err) { + expect(''+err).to.contain("copy is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when drawing a _curve with a Cp2 that is a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new freesewing.Path().withRaise(raise) + const b = new freesewing.Point(10,10) + expect(invalid).to.equal(false); + try { + p1.move(b)._curve('a', b) + } + catch (err) { + expect(''+err).to.contain("copy is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when drawing a curve_ with a To that is a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new freesewing.Path().withRaise(raise) + const b = new freesewing.Point(10,10) + expect(invalid).to.equal(false); + try { + p1.move(b).curve_(b, 'a') + } + catch (err) { + expect(''+err).to.contain("copy is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when drawing a curve_ with a Cp2 that is a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new freesewing.Path().withRaise(raise) + const b = new freesewing.Point(10,10) + expect(invalid).to.equal(false); + try { + p1.move(b).curve_('a', b) + } + catch (err) { + expect(''+err).to.contain("copy is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should add a noop operation", () => { + const p1 = new freesewing.Path().noop() + expect(p1.ops.length).to.equal(1); + expect(p1.ops[0].type).to.equal('noop'); + }); + + it("Should handle an insop operation", () => { + const a = new freesewing.Point(0,0) + const b = new freesewing.Point(10,10) + const p1 = new freesewing.Path().move(a).line(b) + const p2 = new freesewing.Path().noop('test').insop('test', p1) + expect(p2.ops.length).to.equal(2); + expect(p1.ops[0].type).to.equal('move'); + expect(p1.ops[1].type).to.equal('line'); + }); + + it("Should raise a warning when an insop operation used an falsy ID", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const a = new freesewing.Point(0,0) + const b = new freesewing.Point(10,10) + const p1 = new freesewing.Path().move(a).line(b) + expect(invalid).to.equal(false); + const p2 = new freesewing.Path().withRaise(raise).noop('test').insop(false, p1) + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when an insop operation used an falsy ID", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const a = new freesewing.Point(0,0) + const b = new freesewing.Point(10,10) + const p1 = new freesewing.Path().move(a).line(b) + expect(invalid).to.equal(false); + try { + new freesewing.Path().withRaise(raise).noop('test').insop('test') + } + catch (err) { + expect(''+err).to.contain("Cannot read properties of undefined (reading 'ops')") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when setting an attribute without a name", () => { + let invalid = false + const raise = { warning: () => invalid = true } + expect(invalid).to.equal(false); + const p1 = new freesewing.Path().withRaise(raise).attr() + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when setting an attribute without a value", () => { + let invalid = false + const raise = { warning: () => invalid = true } + expect(invalid).to.equal(false); + const p1 = new freesewing.Path().withRaise(raise).attr('test') + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when calling offset without a distance", () => { + const pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + const { Path, Point, points, paths } = pattern.parts.a.shorthand() + points.a = new Point(0,0) + points.b = new Point(10,10) + paths.a = new Path().move(points.a).line(points.b) + paths.b = paths.a.offset() + expect(pattern.events.error.length).to.equal(1) + expect(pattern.events.error[0]).to.equal("Called `Path.offset(distance)` but `distance` is not a number") + }); + + it("Should raise a warning when calling join without a path", () => { + const pattern = new freesewing.Pattern(); + pattern.parts.a = new pattern.Part(); + const { Path, Point, points, paths } = pattern.parts.a.shorthand() + points.a = new Point(0,0) + points.b = new Point(10,10) + try { + //paths.a = new Path().move(points.a).line(points.b).join() + pattern.parts.a.paths.a = new Path().move(points.a).line(points.b).join() + } + catch (err) { + expect(''+err).to.contain("Cannot read properties of undefined (reading 'ops')") + } + expect(pattern.events.error.length).to.equal(1) + expect(pattern.events.error[0]).to.equal("Called `Path.join(that)` but `that` is not a `Path` object") + }); + + it("Should raise a warning when calling start on a path without drawing operations", () => { + let invalid = false + const raise = { error: () => invalid = true } + expect(invalid).to.equal(false); + try { + new freesewing.Path().withRaise(raise).start() + } + catch (err) { + expect(''+err).to.contain("Cannot read properties of undefined (reading 'to')") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when calling end on a path without drawing operations", () => { + let invalid = false + const raise = { error: () => invalid = true } + expect(invalid).to.equal(false); + try { + new freesewing.Path().withRaise(raise).end() + } + catch (err) { + expect(''+err).to.contain("Cannot read properties of undefined (reading 'type')") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when calling shiftAlong but distance is not a number", () => { + let invalid = false + const raise = { error: () => invalid = true } + expect(invalid).to.equal(false); + new freesewing.Path() + .withRaise(raise) + .move(new freesewing.Point(0,0)) + .line(new freesewing.Point(10,10)) + .shiftAlong() + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when calling shiftFractionalong but fraction is not a number", () => { + let invalid = false + const raise = { + error: () => invalid = true, + warning: () => invalid = true, + } + expect(invalid).to.equal(false); + new freesewing.Path() + .withRaise(raise) + .move(new freesewing.Point(0,0).withRaise(raise)) + .line(new freesewing.Point(10,10).withRaise(raise)) + .line(new freesewing.Point(10,20).withRaise(raise)) + .shiftFractionAlong() + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when splitting a path on a non-point", () => { + let invalid = false + const raise = { + error: () => invalid = true, + warning: () => invalid = true, + } + const from = new freesewing.Point(0,0).withRaise(raise) + const cp1 = new freesewing.Point(10,0).withRaise(raise) + const cp2 = new freesewing.Point(90,0).withRaise(raise) + const to = new freesewing.Point(100,0).withRaise(raise) + const path = new freesewing.Path() + .withRaise(raise) + .move(from) + .curve(cp1, cp2, to) + .line(from) + .line(cp1) + try { + path.split() + } + catch (err) { + expect(''+err).to.contain("Cannot read properties of undefined (reading 'check')") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when splitting a path on a non-point", () => { + let invalid = false + const raise = { + error: () => invalid = true, + warning: () => invalid = true, + } + const from = new freesewing.Point(0,0).withRaise(raise) + const cp1 = new freesewing.Point(10,0).withRaise(raise) + const cp2 = new freesewing.Point(90,0).withRaise(raise) + const to = new freesewing.Point(100,0).withRaise(raise) + const path = new freesewing.Path() + .withRaise(raise) + .move(from) + .curve(cp1, cp2, to) + .line(from) + try { + path.split() + } + catch (err) { + expect(''+err).to.contain("Cannot read properties of undefined (reading 'check')") + } + expect(invalid).to.equal(true); + }); }); diff --git a/packages/core/tests/pattern.test.mjs b/packages/core/tests/pattern.test.mjs index 54e243fa4cd..b142b889816 100644 --- a/packages/core/tests/pattern.test.mjs +++ b/packages/core/tests/pattern.test.mjs @@ -3,1137 +3,1154 @@ import freesewing from "./dist/index.mjs" const expect = chai.expect -it("Pattern constructor should initialize object", () => { - let pattern = new freesewing.Pattern({ - foo: "bar", - options: { - constant: 2, - percentage: { pct: 30, min: 0, max: 100 } - } +describe('Pattern', () => { + it("Pattern constructor should initialize object", () => { + let pattern = new freesewing.Pattern({ + foo: "bar", + options: { + constant: 2, + percentage: { pct: 30, min: 0, max: 100 } + } + }); + expect(pattern.width).to.equal(0); + expect(pattern.height).to.equal(0); + expect(pattern.settings.complete).to.equal(true); + expect(pattern.parts).to.eql({}); + expect(pattern.settings.units).to.equal("metric"); + expect(pattern.config.foo).to.equal("bar"); + expect(pattern.settings.options.constant).to.equal(2); + expect(pattern.settings.options.percentage).to.equal(0.3); }); - expect(pattern.width).to.equal(0); - expect(pattern.height).to.equal(0); - expect(pattern.settings.complete).to.equal(true); - expect(pattern.parts).to.eql({}); - expect(pattern.settings.units).to.equal("metric"); - expect(pattern.config.foo).to.equal("bar"); - expect(pattern.settings.options.constant).to.equal(2); - expect(pattern.settings.options.percentage).to.equal(0.3); -}); -it("Should load percentage options", () => { - let pattern = new freesewing.Pattern({ - options: { - test: { pct: 30 } - } + it("Should load percentage options", () => { + let pattern = new freesewing.Pattern({ + options: { + test: { pct: 30 } + } + }); + expect(pattern.settings.options.test).to.equal(0.3); }); - expect(pattern.settings.options.test).to.equal(0.3); -}); -it("Should load millimeter options", () => { - let pattern = new freesewing.Pattern({ - options: { - test: { mm: 30 } - } + it("Should load millimeter options", () => { + let pattern = new freesewing.Pattern({ + options: { + test: { mm: 30 } + } + }); + expect(pattern.settings.options.test).to.equal(30); }); - expect(pattern.settings.options.test).to.equal(30); -}); -it("Should load degree options", () => { - let pattern = new freesewing.Pattern({ - options: { - test: { deg: 15 } - } + it("Should load degree options", () => { + let pattern = new freesewing.Pattern({ + options: { + test: { deg: 15 } + } + }); + expect(pattern.settings.options.test).to.equal(15); }); - expect(pattern.settings.options.test).to.equal(15); -}); -it("Should load an array option", () => { - let pattern = new freesewing.Pattern({ - options: { - test: { dflt: "foo" } - } + it("Should load an array option", () => { + let pattern = new freesewing.Pattern({ + options: { + test: { dflt: "foo" } + } + }); + expect(pattern.settings.options.test).to.equal("foo"); }); - expect(pattern.settings.options.test).to.equal("foo"); -}); -it("Should load a count option", () => { - let pattern = new freesewing.Pattern({ - options: { - test: { count: 3 } - } + it("Should load a count option", () => { + let pattern = new freesewing.Pattern({ + options: { + test: { count: 3 } + } + }); + expect(pattern.settings.options.test).to.equal(3); }); - expect(pattern.settings.options.test).to.equal(3); -}); -it("Should load a boolean option", () => { - let pattern = new freesewing.Pattern({ - options: { - test1: { bool: false }, - test2: { bool: true } - } + it("Should load a boolean option", () => { + let pattern = new freesewing.Pattern({ + options: { + test1: { bool: false }, + test2: { bool: true } + } + }); + expect(pattern.settings.options.test1).to.be.false; + expect(pattern.settings.options.test2).to.be.true; }); - expect(pattern.settings.options.test1).to.be.false; - expect(pattern.settings.options.test2).to.be.true; -}); -it("Should throw an error for an unknown option", () => { - expect( - () => - new freesewing.Pattern({ - options: { - test: { foo: "bar" } + it("Should throw an error for an unknown option", () => { + expect( + () => + new freesewing.Pattern({ + options: { + test: { foo: "bar" } + } + }) + ).to.throw(); + }); + + it("Should merge settings with default settings", () => { + let pattern = new freesewing.Pattern(); + let settings = { + foo: "bar", + deep: { + free: "ze" + } + }; + pattern.apply(settings); + expect(pattern.settings.foo).to.equal("bar"); + expect(pattern.settings.locale).to.equal("en"); + expect(pattern.settings.margin).to.equal(2); + expect(pattern.settings.idPrefix).to.equal("fs-"); + expect(pattern.settings.deep.free).to.equal("ze"); + }); + + it("Should draft according to settings", () => { + let count = 0 + const back = { + name: 'back', + hide: true, + draft: function(part) { + count ++ + return part; + } + } + const front = { + name: 'front', + from: back, + draft: function(part) { + count ++ + return part; + } + } + const Test = new freesewing.Design({ + name: "test", + parts: [ back, front ], + }); + + const pattern = new Test(); + pattern.draft(); + expect(count).to.equal(2); + }); + + it("Should sample an option", () => { + let pattern = new freesewing.Pattern({ + options: { + len: { pct: 30, min: 10 }, + bonus: 10 + } + }); + pattern.draft = function() { + pattern.parts.a = new pattern.Part(); + pattern.parts.b = new pattern.Part(); + let a = pattern.parts.a; + a.points.from = new a.Point(0, 0); + a.points.to = new a.Point( + 100 * a.context.settings.options.len, + a.context.settings.options.bonus + ); + a.paths.test = new a.Path().move(a.points.from).line(a.points.to); + pattern.parts.b.inject(a); + }; + pattern.settings.sample = { + type: "option", + option: "len" + }; + pattern.sample(); + expect(pattern.parts.a.paths.test_1.render).to.equal(true); + expect(pattern.parts.b.paths.test_10.ops[1].to.y).to.equal(10); + }); +/* + it("Should sample a list option", () => { + const front = { + name: 'front', + options: { + len: { + dflt: 1, + list: [1,2,3] } - }) - ).to.throw(); -}); - -it("Should merge settings with default settings", () => { - let pattern = new freesewing.Pattern(); - let settings = { - foo: "bar", - deep: { - free: "ze" - } - }; - pattern.apply(settings); - expect(pattern.settings.foo).to.equal("bar"); - expect(pattern.settings.locale).to.equal("en"); - expect(pattern.settings.margin).to.equal(2); - expect(pattern.settings.idPrefix).to.equal("fs-"); - expect(pattern.settings.deep.free).to.equal("ze"); -}); - -it("Should draft according to settings", () => { - const Test = new freesewing.Design({ - name: "test", - dependencies: { back: "front" }, - inject: { back: "front" }, - hide: ["back"] - }); - Test.prototype.draftBack = function(part) { - this.count++; - return part; - }; - Test.prototype.draftFront = function(part) { - this.count++; - return part; - }; - - let pattern = new Test(); - pattern.count = 0; - pattern.draft(); - expect(pattern.count).to.equal(2); -}); - -it("Should throw an error if per-part draft method is missing", () => { - const Test = new freesewing.Design({ - name: "test", - dependencies: { back: "front" }, - inject: { back: "front" }, - hide: ["back"] - }); - Test.prototype.draftBack = part => part; - let pattern = new Test(); - expect(() => pattern.draft()).to.throw(); -}); - -it("Should sample an option", () => { - let pattern = new freesewing.Pattern({ - options: { - len: { pct: 30, min: 10 }, - bonus: 10 - } - }); - pattern.draft = function() { - pattern.parts.a = new pattern.Part(); - pattern.parts.b = new pattern.Part(); - let a = pattern.parts.a; - a.points.from = new a.Point(0, 0); - a.points.to = new a.Point( - 100 * a.context.settings.options.len, - a.context.settings.options.bonus - ); - a.paths.test = new a.Path().move(a.points.from).line(a.points.to); - pattern.parts.b.inject(a); - }; - pattern.settings.sample = { - type: "option", - option: "len" - }; - pattern.sample(); - expect(pattern.parts.a.paths.test_1.render).to.equal(true); - expect(pattern.parts.b.paths.test_10.ops[1].to.y).to.equal(10); -}); - -it("Should sample a list option", () => { - const Test = new freesewing.Design({ - name: "test", - parts: ['front'], - options: { - len: { - dflt: 1, - list: [1,2,3] - } - }, - }) - Test.prototype.draftFront = function(part) { - const { Point, points, Path, paths, options } = part.shorthand() - points.from = new Point(0, 0); - points.to = new Point( 100 * options.len, 0) - paths.line = new Path() - .move(points.from) - .line(points.to) - - return part - }; - const pattern = new Test({ - sample: { - type: 'option', - option: 'len' - } - }) - pattern.sample(); - expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(100); - expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(200); - expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(300); -}); - -it("Should sample a measurement", () => { - const Test = new freesewing.Design({ - name: "test", - parts: ['front'], - measurements: ['head'] - }) - Test.prototype.draftFront = function(part) { - const { Point, points, Path, paths, measurements } = part.shorthand() - points.from = new Point(0, 0); - points.to = new Point( measurements.head, 0) - paths.line = new Path() - .move(points.from) - .line(points.to) - - return part - }; - const pattern = new Test({ - measurements: { - head: 100 - }, - sample: { - type: 'measurement', - measurement: 'head' - } - }) - pattern.sample(); - expect(pattern.is).to.equal('sample') - expect(pattern.events.debug[0]).to.equal('Sampling measurement `head`') - for (let i=0;i<10;i++) { - const j = i + 1 - expect(pattern.parts.front.paths[`line_${j}`].ops[1].to.x).to.equal(90 + 2*i); - } - pattern.sampleMeasurement('nope') - expect(pattern.events.error.length).to.equal(1) - expect(pattern.events.error[0]).to.equal("Cannot sample measurement `nope` because it's `undefined`") -}); - -it("Should sample models", () => { - const Test = new freesewing.Design({ - name: "test", - parts: ['front'], - measurements: ['head'] - }) - Test.prototype.draftFront = function(part) { - const { Point, points, Path, paths, measurements } = part.shorthand() - points.from = new Point(0, 0); - points.to = new Point( measurements.head, 0) - paths.line = new Path() - .move(points.from) - .line(points.to) - - return part - }; - let pattern = new Test({ - sample: { - type: 'models', - models : { - a: { head: 100 }, - b: { head: 50 }, - } - } - }) - pattern.sample(); - expect(pattern.is).to.equal('sample') - expect(pattern.events.debug[0]).to.equal('Sampling models') - expect(pattern.parts.front.paths[`line_0`].ops[1].to.x).to.equal(100); - expect(pattern.parts.front.paths[`line_1`].ops[1].to.x).to.equal(50); - pattern = new Test({ - sample: { - type: 'models', - models : { - a: { head: 100 }, - b: { head: 50 }, }, - focus: 'b' - } - }) - pattern.sample(); - expect(pattern.is).to.equal('sample') - expect(pattern.parts.front.paths[`line_-1`].ops[1].to.x).to.equal(50); - expect(pattern.parts.front.paths[`line_0`].ops[1].to.x).to.equal(100); -}); + draft: function(part) { + const { Point, points, Path, paths, options } = part.shorthand() + points.from = new Point(0, 0); + points.to = new Point( 100 * options.len, 0) + paths.line = new Path() + .move(points.from) + .line(points.to) -it("Should register a hook via on", () => { - let pattern = new freesewing.Pattern(); - let count = 0; - pattern._draft = () => {}; - pattern.on("preDraft", function(pattern) { - count++; - }); - pattern.draft(); - expect(count).to.equal(1); -}); - -it("Should register a hook from a plugin", () => { - let pattern = new freesewing.Pattern(); - let count = 0; - pattern._draft = () => {}; - let plugin = { - name: "test", - version: "0.1-test", - hooks: { - preDraft: function(pattern) { - count++; + return part } } - }; - pattern.use(plugin); - pattern.draft(); - expect(count).to.equal(1); -}); + const Test = new freesewing.Design({ + name: "test", + parts: [front], + }) + const pattern = new Test({ + sample: { + type: 'option', + option: 'len' + } + }) + pattern.sample(); + console.log(pattern.parts) + expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(100); + expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(200); + expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(300); + }); -it("Should register multiple methods on a single hook", () => { - let pattern = new freesewing.Pattern(); - let count = 0; - pattern._draft = () => {}; - let plugin = { - name: "test", - version: "0.1-test", - hooks: { - preDraft: [ - function(pattern) { - count++; + it("Should sample a measurement", () => { + const Test = new freesewing.Design({ + name: "test", + parts: ['front'], + measurements: ['head'] + }) + Test.prototype.draftFront = function(part) { + const { Point, points, Path, paths, measurements } = part.shorthand() + points.from = new Point(0, 0); + points.to = new Point( measurements.head, 0) + paths.line = new Path() + .move(points.from) + .line(points.to) + + return part + }; + const pattern = new Test({ + measurements: { + head: 100 + }, + sample: { + type: 'measurement', + measurement: 'head' + } + }) + pattern.sample(); + expect(pattern.is).to.equal('sample') + expect(pattern.events.debug[0]).to.equal('Sampling measurement `head`') + for (let i=0;i<10;i++) { + const j = i + 1 + expect(pattern.parts.front.paths[`line_${j}`].ops[1].to.x).to.equal(90 + 2*i); + } + pattern.sampleMeasurement('nope') + expect(pattern.events.error.length).to.equal(1) + expect(pattern.events.error[0]).to.equal("Cannot sample measurement `nope` because it's `undefined`") + }); + + it("Should sample models", () => { + const Test = new freesewing.Design({ + name: "test", + parts: ['front'], + measurements: ['head'] + }) + Test.prototype.draftFront = function(part) { + const { Point, points, Path, paths, measurements } = part.shorthand() + points.from = new Point(0, 0); + points.to = new Point( measurements.head, 0) + paths.line = new Path() + .move(points.from) + .line(points.to) + + return part + }; + let pattern = new Test({ + sample: { + type: 'models', + models : { + a: { head: 100 }, + b: { head: 50 }, + } + } + }) + pattern.sample(); + expect(pattern.is).to.equal('sample') + expect(pattern.events.debug[0]).to.equal('Sampling models') + expect(pattern.parts.front.paths[`line_0`].ops[1].to.x).to.equal(100); + expect(pattern.parts.front.paths[`line_1`].ops[1].to.x).to.equal(50); + pattern = new Test({ + sample: { + type: 'models', + models : { + a: { head: 100 }, + b: { head: 50 }, }, - function(pattern) { + focus: 'b' + } + }) + pattern.sample(); + expect(pattern.is).to.equal('sample') + expect(pattern.parts.front.paths[`line_-1`].ops[1].to.x).to.equal(50); + expect(pattern.parts.front.paths[`line_0`].ops[1].to.x).to.equal(100); + }); + */ + + it("Should register a hook via on", () => { + let pattern = new freesewing.Pattern(); + let count = 0; + pattern._draft = () => {}; + pattern.on("preDraft", function(pattern) { + count++; + }); + pattern.draft(); + expect(count).to.equal(1); + }); + + it("Should register a hook from a plugin", () => { + let pattern = new freesewing.Pattern(); + let count = 0; + pattern._draft = () => {}; + let plugin = { + name: "test", + version: "0.1-test", + hooks: { + preDraft: function(pattern) { count++; } + } + }; + pattern.use(plugin); + pattern.draft(); + expect(count).to.equal(1); + }); + + it("Should register multiple methods on a single hook", () => { + let pattern = new freesewing.Pattern(); + let count = 0; + pattern._draft = () => {}; + let plugin = { + name: "test", + version: "0.1-test", + hooks: { + preDraft: [ + function(pattern) { + count++; + }, + function(pattern) { + count++; + } + ] + } + }; + pattern.use(plugin); + pattern.draft(); + expect(count).to.equal(2); + }); + + it("Should check whether a part is needed", () => { + let config = { + name: "test", + dependencies: { back: "front", side: "back" }, + inject: { back: "front" }, + hide: ["back"] + }; + const Test = new freesewing.Design(config) + Test.prototype.draftBack = function(part) { + return part; + }; + Test.prototype.draftFront = function(part) { + return part; + }; + + let pattern = new Test().init(); + pattern.settings.only = "back"; + //expect(pattern.needs("back")).to.equal(true); + expect(pattern.needs("front")).to.equal(true); + //expect(pattern.needs("side")).to.equal(false); + //pattern.settings.only = ["back", "side"]; + //expect(pattern.needs("back")).to.equal(true); + //expect(pattern.needs("front")).to.equal(true); + //expect(pattern.needs("side")).to.equal(true); + }); + + it("Should check whether a part is wanted", () => { + let config = { + name: "test", + dependencies: { back: "front", side: "back" }, + inject: { back: "front" }, + hide: ["back"] + }; + const Test = function(settings = false) { + freesewing.Pattern.call(this, config); + return this; + }; + Test.prototype = Object.create(freesewing.Pattern.prototype); + Test.prototype.constructor = Test; + Test.prototype.draftBack = function(part) { + return part; + }; + Test.prototype.draftFront = function(part) { + return part; + }; + + let pattern = new Test(); + pattern.settings.only = "back"; + expect(pattern.wants("back")).to.equal(true); + expect(pattern.wants("front")).to.equal(false); + expect(pattern.wants("side")).to.equal(false); + pattern.settings.only = ["back", "side"]; + expect(pattern.wants("back")).to.equal(true); + expect(pattern.wants("front")).to.equal(false); + expect(pattern.wants("side")).to.equal(true); + }); + + it("Should correctly resolve dependencies - string version", () => { + let config = { + name: "test", + dependencies: { front: "back", side: "back", hood: "front", stripe: "hood" }, + }; + const Test = new freesewing.Design(config) + Test.prototype = Object.create(freesewing.Pattern.prototype); + Test.prototype.constructor = Test; + Test.prototype.draftBack = function(part) { + return part; + }; + Test.prototype.draftFront = function(part) { + return part; + }; + + let pattern = new Test().init(); + expect(pattern.config.resolvedDependencies.front.length).to.equal(1); + expect(pattern.config.resolvedDependencies.front[0]).to.equal('back'); + expect(pattern.config.resolvedDependencies.side.length).to.equal(1); + expect(pattern.config.resolvedDependencies.side[0]).to.equal('back'); + expect(pattern.config.resolvedDependencies.hood.length).to.equal(2); + expect(pattern.config.resolvedDependencies.hood[0]).to.equal('front'); + expect(pattern.config.resolvedDependencies.hood[1]).to.equal('back'); + expect(pattern.config.resolvedDependencies.stripe.length).to.equal(3); + expect(pattern.config.resolvedDependencies.stripe[0]).to.equal('hood'); + expect(pattern.config.resolvedDependencies.stripe[1]).to.equal('front'); + expect(pattern.config.resolvedDependencies.stripe[2]).to.equal('back'); + expect(pattern.config.resolvedDependencies.back.length).to.equal(0); + expect(pattern.config.draftOrder[0]).to.equal('back'); + expect(pattern.config.draftOrder[1]).to.equal('front'); + expect(pattern.config.draftOrder[2]).to.equal('side'); + expect(pattern.config.draftOrder[3]).to.equal('hood'); + }); + + it("Should correctly resolve dependencies - array version", () => { + let config = { + name: "test", + dependencies: { front: ["back"], side: ["back"], hood: ["front"], stripe: ["hood"]}, + }; + const Test = function(settings = false) { + freesewing.Pattern.call(this, config); + return this; + }; + Test.prototype = Object.create(freesewing.Pattern.prototype); + Test.prototype.constructor = Test; + Test.prototype.draftBack = function(part) { + return part; + }; + Test.prototype.draftFront = function(part) { + return part; + }; + + let pattern = new Test().init(); + expect(pattern.config.resolvedDependencies.front.length).to.equal(1); + expect(pattern.config.resolvedDependencies.front[0]).to.equal('back'); + expect(pattern.config.resolvedDependencies.side.length).to.equal(1); + expect(pattern.config.resolvedDependencies.side[0]).to.equal('back'); + expect(pattern.config.resolvedDependencies.hood.length).to.equal(2); + expect(pattern.config.resolvedDependencies.hood[0]).to.equal('front'); + expect(pattern.config.resolvedDependencies.hood[1]).to.equal('back'); + expect(pattern.config.resolvedDependencies.stripe.length).to.equal(3); + expect(pattern.config.resolvedDependencies.stripe[0]).to.equal('hood'); + expect(pattern.config.resolvedDependencies.stripe[1]).to.equal('front'); + expect(pattern.config.resolvedDependencies.stripe[2]).to.equal('back'); + expect(pattern.config.resolvedDependencies.back.length).to.equal(0); + expect(pattern.config.draftOrder[0]).to.equal('back'); + expect(pattern.config.draftOrder[1]).to.equal('front'); + expect(pattern.config.draftOrder[2]).to.equal('side'); + expect(pattern.config.draftOrder[3]).to.equal('hood'); + }); + + it("Should correctly resolve dependencies - issue #971 - working version", () => { + let config = { + name: "test", + dependencies: {front:['back'],crotch:['front','back']}, + parts: ['back','front','crotch'], + }; + const Test = function(settings = false) { + freesewing.Pattern.call(this, config); + return this; + }; + Test.prototype = Object.create(freesewing.Pattern.prototype); + Test.prototype.constructor = Test; + Test.prototype.draftBack = function(part) { + return part; + }; + Test.prototype.draftFront = function(part) { + return part; + }; + + let pattern = new Test().init(); + expect(pattern.config.draftOrder[0]).to.equal('back'); + expect(pattern.config.draftOrder[1]).to.equal('front'); + expect(pattern.config.draftOrder[2]).to.equal('crotch'); + }); + + it("Should correctly resolve dependencies - issue #971 - broken version", () => { + let config = { + name: "test", + dependencies: {front:'back',crotch:['front','back']}, + parts: ['back','front','crotch'], + }; + const Test = function(settings = false) { + freesewing.Pattern.call(this, config); + return this; + }; + Test.prototype = Object.create(freesewing.Pattern.prototype); + Test.prototype.constructor = Test; + Test.prototype.draftBack = function(part) { + return part; + }; + Test.prototype.draftFront = function(part) { + return part; + }; + + let pattern = new Test().init(); + expect(pattern.config.draftOrder[0]).to.equal('back'); + expect(pattern.config.draftOrder[1]).to.equal('front'); + expect(pattern.config.draftOrder[2]).to.equal('crotch'); + }); + + it("Should correctly resolve dependencies - Handle uncovered code path", () => { + let config = { + name: "test", + dependencies: { + front: 'side', + crotch:['front','back'], + back: 1, + }, + inject: { + front: 'back', + }, + parts: ['back','front','crotch'], + }; + const Test = function(settings = false) { + freesewing.Pattern.call(this, config); + return this; + }; + Test.prototype = Object.create(freesewing.Pattern.prototype); + Test.prototype.constructor = Test; + Test.prototype.draftBack = function(part) { + return part; + }; + Test.prototype.draftFront = function(part) { + return part; + }; + + let pattern = new Test().init(); + const deps = pattern.resolveDependencies() + expect(pattern.config.draftOrder[0]).to.equal('side'); + expect(pattern.config.draftOrder[1]).to.equal('back'); + expect(pattern.config.draftOrder[2]).to.equal('front'); + }); + + it("Should check whether created parts get the pattern context", () => { + let pattern = new freesewing.Pattern(); + let part = new pattern.Part(); + expect(part.context.settings).to.equal(pattern.settings); + }); + + it("Should correctly merge settings", () => { + let pattern = new freesewing.Pattern(); + let settings = { + complete: false, + only: [1, 2, 3], + margin: 5 + }; + pattern.apply(settings); + expect(pattern.settings.complete).to.equal(false); + expect(pattern.settings.only[1]).to.equal(2); + expect(pattern.settings.margin).to.equal(5); + expect(pattern.settings.only.length).to.equal(3); + }); + + it("Should correctly merge settings for existing array", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.only = [1]; + let settings = { + complete: false, + only: [2, 3, 4], + margin: 5 + }; + pattern.apply(settings); + expect(pattern.settings.complete).to.equal(false); + expect(pattern.settings.only.length).to.equal(4); + expect(pattern.settings.margin).to.equal(5); + }); + + it("Should return all render props", () => { + const front = { + name: 'front', + draft: function(part) { return part } + } + const Test = new freesewing.Design({ + name: "test", + parts: [front], + }); + const pattern = new Test() + pattern.draft(); + const rp = pattern.getRenderProps() + expect(rp.svg.body).to.equal(''); + expect(rp.width).to.equal(4); + expect(rp.height).to.equal(4); + expect(rp.parts.front.height).to.equal(4); + }); + + it("Should not pack a pattern with errors", () => { + const pattern = new freesewing.Pattern() + pattern.events.error.push('error') + pattern.pack() + expect(pattern.events.warning.length).to.equal(1) + expect(pattern.events.warning[0]).to.equal('One or more errors occured. Not packing pattern parts') + }); + + /* + it("Should generate an auto layout if there is no set layout", () => { + const Test = new freesewing.Design({ + name: "test", + parts: [ + { + name: 'front', + draft: function(part) { + const {Path, paths, Point} = part.shorthand() + paths.seam = new Path().move(new Point(0,0)) + .line(new Point(5,5)) + return part + } + } ] - } - }; - pattern.use(plugin); - pattern.draft(); - expect(count).to.equal(2); -}); + }) + const pattern = new Test() + pattern.parts.front = new pattern.Part('front') + pattern.draftFront(pattern.parts.front); + pattern.pack() + expect(pattern.autoLayout.parts.front).to.exist + expect(pattern.autoLayout.parts.front.move.y).to.equal(2) + expect(pattern.autoLayout.parts.front.move.x).to.equal(2) + }) + */ -it("Should check whether a part is needed", () => { - let config = { - name: "test", - dependencies: { back: "front", side: "back" }, - inject: { back: "front" }, - hide: ["back"] - }; - const Test = new freesewing.Design(config) - Test.prototype.draftBack = function(part) { - return part; - }; - Test.prototype.draftFront = function(part) { - return part; - }; - - let pattern = new Test().init(); - pattern.settings.only = "back"; - //expect(pattern.needs("back")).to.equal(true); - expect(pattern.needs("front")).to.equal(true); - //expect(pattern.needs("side")).to.equal(false); - //pattern.settings.only = ["back", "side"]; - //expect(pattern.needs("back")).to.equal(true); - //expect(pattern.needs("front")).to.equal(true); - //expect(pattern.needs("side")).to.equal(true); -}); - -it("Should check whether a part is wanted", () => { - let config = { - name: "test", - dependencies: { back: "front", side: "back" }, - inject: { back: "front" }, - hide: ["back"] - }; - const Test = function(settings = false) { - freesewing.Pattern.call(this, config); - return this; - }; - Test.prototype = Object.create(freesewing.Pattern.prototype); - Test.prototype.constructor = Test; - Test.prototype.draftBack = function(part) { - return part; - }; - Test.prototype.draftFront = function(part) { - return part; - }; - - let pattern = new Test(); - pattern.settings.only = "back"; - expect(pattern.wants("back")).to.equal(true); - expect(pattern.wants("front")).to.equal(false); - expect(pattern.wants("side")).to.equal(false); - pattern.settings.only = ["back", "side"]; - expect(pattern.wants("back")).to.equal(true); - expect(pattern.wants("front")).to.equal(false); - expect(pattern.wants("side")).to.equal(true); -}); - -it("Should correctly resolve dependencies - string version", () => { - let config = { - name: "test", - dependencies: { front: "back", side: "back", hood: "front", stripe: "hood" }, - }; - const Test = new freesewing.Design(config) - Test.prototype = Object.create(freesewing.Pattern.prototype); - Test.prototype.constructor = Test; - Test.prototype.draftBack = function(part) { - return part; - }; - Test.prototype.draftFront = function(part) { - return part; - }; - - let pattern = new Test().init(); - expect(pattern.config.resolvedDependencies.front.length).to.equal(1); - expect(pattern.config.resolvedDependencies.front[0]).to.equal('back'); - expect(pattern.config.resolvedDependencies.side.length).to.equal(1); - expect(pattern.config.resolvedDependencies.side[0]).to.equal('back'); - expect(pattern.config.resolvedDependencies.hood.length).to.equal(2); - expect(pattern.config.resolvedDependencies.hood[0]).to.equal('front'); - expect(pattern.config.resolvedDependencies.hood[1]).to.equal('back'); - expect(pattern.config.resolvedDependencies.stripe.length).to.equal(3); - expect(pattern.config.resolvedDependencies.stripe[0]).to.equal('hood'); - expect(pattern.config.resolvedDependencies.stripe[1]).to.equal('front'); - expect(pattern.config.resolvedDependencies.stripe[2]).to.equal('back'); - expect(pattern.config.resolvedDependencies.back.length).to.equal(0); - expect(pattern.config.draftOrder[0]).to.equal('back'); - expect(pattern.config.draftOrder[1]).to.equal('front'); - expect(pattern.config.draftOrder[2]).to.equal('side'); - expect(pattern.config.draftOrder[3]).to.equal('hood'); -}); - -it("Should correctly resolve dependencies - array version", () => { - let config = { - name: "test", - dependencies: { front: ["back"], side: ["back"], hood: ["front"], stripe: ["hood"]}, - }; - const Test = function(settings = false) { - freesewing.Pattern.call(this, config); - return this; - }; - Test.prototype = Object.create(freesewing.Pattern.prototype); - Test.prototype.constructor = Test; - Test.prototype.draftBack = function(part) { - return part; - }; - Test.prototype.draftFront = function(part) { - return part; - }; - - let pattern = new Test().init(); - expect(pattern.config.resolvedDependencies.front.length).to.equal(1); - expect(pattern.config.resolvedDependencies.front[0]).to.equal('back'); - expect(pattern.config.resolvedDependencies.side.length).to.equal(1); - expect(pattern.config.resolvedDependencies.side[0]).to.equal('back'); - expect(pattern.config.resolvedDependencies.hood.length).to.equal(2); - expect(pattern.config.resolvedDependencies.hood[0]).to.equal('front'); - expect(pattern.config.resolvedDependencies.hood[1]).to.equal('back'); - expect(pattern.config.resolvedDependencies.stripe.length).to.equal(3); - expect(pattern.config.resolvedDependencies.stripe[0]).to.equal('hood'); - expect(pattern.config.resolvedDependencies.stripe[1]).to.equal('front'); - expect(pattern.config.resolvedDependencies.stripe[2]).to.equal('back'); - expect(pattern.config.resolvedDependencies.back.length).to.equal(0); - expect(pattern.config.draftOrder[0]).to.equal('back'); - expect(pattern.config.draftOrder[1]).to.equal('front'); - expect(pattern.config.draftOrder[2]).to.equal('side'); - expect(pattern.config.draftOrder[3]).to.equal('hood'); -}); - -it("Should correctly resolve dependencies - issue #971 - working version", () => { - let config = { - name: "test", - dependencies: {front:['back'],crotch:['front','back']}, - parts: ['back','front','crotch'], - }; - const Test = function(settings = false) { - freesewing.Pattern.call(this, config); - return this; - }; - Test.prototype = Object.create(freesewing.Pattern.prototype); - Test.prototype.constructor = Test; - Test.prototype.draftBack = function(part) { - return part; - }; - Test.prototype.draftFront = function(part) { - return part; - }; - - let pattern = new Test().init(); - expect(pattern.config.draftOrder[0]).to.equal('back'); - expect(pattern.config.draftOrder[1]).to.equal('front'); - expect(pattern.config.draftOrder[2]).to.equal('crotch'); -}); - -it("Should correctly resolve dependencies - issue #971 - broken version", () => { - let config = { - name: "test", - dependencies: {front:'back',crotch:['front','back']}, - parts: ['back','front','crotch'], - }; - const Test = function(settings = false) { - freesewing.Pattern.call(this, config); - return this; - }; - Test.prototype = Object.create(freesewing.Pattern.prototype); - Test.prototype.constructor = Test; - Test.prototype.draftBack = function(part) { - return part; - }; - Test.prototype.draftFront = function(part) { - return part; - }; - - let pattern = new Test().init(); - expect(pattern.config.draftOrder[0]).to.equal('back'); - expect(pattern.config.draftOrder[1]).to.equal('front'); - expect(pattern.config.draftOrder[2]).to.equal('crotch'); -}); - -it("Should correctly resolve dependencies - Handle uncovered code path", () => { - let config = { - name: "test", - dependencies: { - front: 'side', - crotch:['front','back'], - back: 1, - }, - inject: { - front: 'back', - }, - parts: ['back','front','crotch'], - }; - const Test = function(settings = false) { - freesewing.Pattern.call(this, config); - return this; - }; - Test.prototype = Object.create(freesewing.Pattern.prototype); - Test.prototype.constructor = Test; - Test.prototype.draftBack = function(part) { - return part; - }; - Test.prototype.draftFront = function(part) { - return part; - }; - - let pattern = new Test().init(); - const deps = pattern.resolveDependencies() - expect(pattern.config.draftOrder[0]).to.equal('side'); - expect(pattern.config.draftOrder[1]).to.equal('back'); - expect(pattern.config.draftOrder[2]).to.equal('front'); -}); - -it("Should check whether created parts get the pattern context", () => { - let pattern = new freesewing.Pattern(); - let part = new pattern.Part(); - expect(part.context.settings).to.equal(pattern.settings); -}); - -it("Should correctly merge settings", () => { - let pattern = new freesewing.Pattern(); - let settings = { - complete: false, - only: [1, 2, 3], - margin: 5 - }; - pattern.apply(settings); - expect(pattern.settings.complete).to.equal(false); - expect(pattern.settings.only[1]).to.equal(2); - expect(pattern.settings.margin).to.equal(5); - expect(pattern.settings.only.length).to.equal(3); -}); - -it("Should correctly merge settings for existing array", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.only = [1]; - let settings = { - complete: false, - only: [2, 3, 4], - margin: 5 - }; - pattern.apply(settings); - expect(pattern.settings.complete).to.equal(false); - expect(pattern.settings.only.length).to.equal(4); - expect(pattern.settings.margin).to.equal(5); -}); - -it("Should return all render props", () => { - const Test = new freesewing.Design({ - name: "test", - parts: ['front'], + it("Should handle custom layouts", () => { + const Test = new freesewing.Design({ name: "test", parts: ['front'] }) + Test.prototype.draftFront = function(part) { return part } + const pattern = new Test({ + layout: { + width: 400, + height: 200, + parts: { front: { move: { x: 14, y: -202 } } } + } + }) + pattern.pack() + expect(pattern.width).to.equal(400) + expect(pattern.height).to.equal(200) }); - Test.prototype.draftFront = function(part) { - return part; - }; - const pattern = new Test() - pattern.draft(); - const rp = pattern.getRenderProps() - expect(rp.svg.body).to.equal(''); - expect(rp.width).to.equal(4); - expect(rp.height).to.equal(4); - expect(rp.parts.front.height).to.equal(4); -}); -it("Should not pack a pattern with errors", () => { - const pattern = new freesewing.Pattern() - pattern.events.error.push('error') - pattern.pack() - expect(pattern.events.warning.length).to.equal(1) - expect(pattern.events.warning[0]).to.equal('One or more errors occured. Not packing pattern parts') -}); - -it("Should generate an auto layout if there is no set layout", () => { - const Test = new freesewing.Design({ name: "test", parts: ['front'] }) - Test.prototype.draftFront = function(part) { - const {Path, paths, Point} = part.shorthand() - paths.seam = new Path().move(new Point(0,0)) - .line(new Point(5,5)) - return part - } - const pattern = new Test() - pattern.parts.front = new pattern.Part('front') - pattern.draftFront(pattern.parts.front); - pattern.pack() - expect(pattern.autoLayout.parts.front).to.exist - expect(pattern.autoLayout.parts.front.move.y).to.equal(2) - expect(pattern.autoLayout.parts.front.move.x).to.equal(2) -}) - -it("Should handle custom layouts", () => { - const Test = new freesewing.Design({ name: "test", parts: ['front'] }) - Test.prototype.draftFront = function(part) { return part } - const pattern = new Test({ - layout: { - width: 400, - height: 200, - parts: { front: { move: { x: 14, y: -202 } } } - } - }) - pattern.pack() - expect(pattern.width).to.equal(400) - expect(pattern.height).to.equal(200) -}); - -it("Should handle a simple snapped option", () => { - const Test = new freesewing.Design({ - name: "test", - parts: ['front'], - measurements: [ 'head' ], - options: { - len: { pct: 50, min: 22, max: 78, snap: 10, ...freesewing.pctBasedOn('head') } - } - }) - Test.prototype.draftFront = function(part) { - const { Point, points, Path, paths, absoluteOptions } = part.shorthand() - points.from = new Point(0, 0); - points.to = new Point( 2 * absoluteOptions.len, 0) - paths.line = new Path() - .move(points.from) - .line(points.to) - - return part - }; - let pattern = new Test({ - sample: { - type: 'option', - option: 'len' - }, - measurements: { - head: 43.23 - } - }) - pattern.sample(); - expect(pattern.is).to.equal('sample') - expect(pattern.events.debug[0]).to.equal('Sampling option `len`') - expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(20); - expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(40); - expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(40); - expect(pattern.parts.front.paths.line_4.ops[1].to.x).to.equal(40); - expect(pattern.parts.front.paths.line_5.ops[1].to.x).to.equal(60); - expect(pattern.parts.front.paths.line_6.ops[1].to.x).to.equal(60); - expect(pattern.parts.front.paths.line_7.ops[1].to.x).to.equal(60); - expect(pattern.parts.front.paths.line_8.ops[1].to.x).to.equal(60); - expect(pattern.parts.front.paths.line_9.ops[1].to.x).to.equal(80); - expect(pattern.parts.front.paths.line_10.ops[1].to.x).to.equal(80); -}); - -it("Should handle a list snapped option", () => { - const Test = new freesewing.Design({ - name: "test", - parts: ['front'], - measurements: [ 'head' ], - options: { - len: { pct: 50, min: 22, max: 78, snap: [10,14,19,28], ...freesewing.pctBasedOn('head') } - } - }) - Test.prototype.draftFront = function(part) { - const { Point, points, Path, paths, absoluteOptions } = part.shorthand() - points.from = new Point(0, 0); - points.to = new Point( absoluteOptions.len, 0) - paths.line = new Path() - .move(points.from) - .line(points.to) - - return part - }; - let pattern = new Test({ - sample: { - type: 'option', - option: 'len' - }, - measurements: { - head: 43.23 - } - }) - pattern.sample(); - expect(pattern.is).to.equal('sample') - expect(pattern.events.debug[0]).to.equal('Sampling option `len`') - expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(10); - expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(14); - expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(14); - expect(pattern.parts.front.paths.line_4.ops[1].to.x).to.equal(19); - expect(pattern.parts.front.paths.line_5.ops[1].to.x).to.equal(19); - expect(pattern.parts.front.paths.line_6.ops[1].to.x).to.equal(19); - expect(pattern.parts.front.paths.line_7.ops[1].to.x).to.equal(28); - expect(pattern.parts.front.paths.line_8.ops[1].to.x).to.equal(28); - expect(pattern.parts.front.paths.line_9.ops[1].to.x).to.equal(28); - expect(freesewing.utils.round(pattern.parts.front.paths.line_10.ops[1].to.x)).to.equal(33.72); -}); - - -it("Should retrieve the cutList", () => { - const Test = new freesewing.Design({ - name: "test", - parts: ['front'], - }) - Test.prototype.draftFront = function(part) { - part.addCut(4, 'lining', true) - - return part - }; - const pattern = new Test() - expect(JSON.stringify(pattern.getCutList())).to.equal(JSON.stringify({})) - pattern.draft() - const list = `{"front":{"grain":90,"materials":{"lining":{"cut":4,"identical":true}}}}` - expect(JSON.stringify(pattern.getCutList())).to.equal(list) -}); - -// 2022 style part inheritance -// I am aware this does too much for one unit test, but this is to simplify TDD -// we can split it up later -it("Design constructor should resolve nested injections (2022)", () => { - const partA = { - name: "partA", - options: { optionA: { bool: true } }, - measurements: [ 'measieA' ], - optionalMeasurements: [ 'optmeasieA' ], - draft: part => { - const { points, Point, paths, Path } = part.shorthand() - points.a1 = new Point(1,1) - points.a2 = new Point(11,11) - paths.a = new Path().move(points.a1).line(points.a2) - return part - } - } - const partB = { - name: "partB", - from: partA, - options: { optionB: { pct: 12, min: 2, max: 20 } }, - measurements: [ 'measieB' ], - optionalMeasurements: [ 'optmeasieB', 'measieA' ], - draft: part => { - const { points, Point, paths, Path } = part.shorthand() - points.b1 = new Point(2,2) - points.b2 = new Point(22,22) - paths.b = new Path().move(points.b1).line(points.b2) - return part - } - } - const partC = { - name: "partC", - from: partB, - options: { optionC: { deg: 5, min: 0, max: 15 } }, - measurements: [ 'measieC' ], - optionalMeasurements: [ 'optmeasieC', 'measieA' ], - draft: part => { - const { points, Point, paths, Path } = part.shorthand() - points.c1 = new Point(3,3) - points.c2 = new Point(33,33) - paths.c = new Path().move(points.c1).line(points.c2) - return part - } - } - const partR = { // R for runtime, which is when this wil be attached - name: "partR", - from: partA, - after: partC, - options: { optionR: { dflt: 'red', list: ['red', 'green', 'blue'] } }, - measurements: [ 'measieR' ], - optionalMeasurements: [ 'optmeasieR', 'measieA' ], - draft: part => { - const { points, Point, paths, Path } = part.shorthand() - points.r1 = new Point(4,4) - points.r2 = new Point(44,44) - paths.r = new Path().move(points.r1).line(points.r2) - return part - } - } - - const Design = new freesewing.Design({ parts: [ partC ] }); - const pattern = new Design().addPart(partR).draft() - // Measurements - expect(pattern.config.measurements.length).to.equal(4) - expect(pattern.config.measurements.indexOf('measieA') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieB') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieC') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieR') === -1).to.equal(false) - // Optional measurements - expect(pattern.config.optionalMeasurements.length).to.equal(4) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieA') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieB') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieC') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieR') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('measieA') === -1).to.equal(true) - // Options - expect(pattern.config.options.optionA.bool).to.equal(true) - expect(pattern.config.options.optionB.pct).to.equal(12) - expect(pattern.config.options.optionB.min).to.equal(2) - expect(pattern.config.options.optionB.max).to.equal(20) - expect(pattern.config.options.optionC.deg).to.equal(5) - expect(pattern.config.options.optionC.min).to.equal(0) - expect(pattern.config.options.optionC.max).to.equal(15) - expect(pattern.config.options.optionR.dflt).to.equal('red') - expect(pattern.config.options.optionR.list[0]).to.equal('red') - expect(pattern.config.options.optionR.list[1]).to.equal('green') - expect(pattern.config.options.optionR.list[2]).to.equal('blue') - // Dependencies - expect(pattern.config.dependencies.partB[0]).to.equal('partA') - expect(pattern.config.dependencies.partC[0]).to.equal('partB') - expect(pattern.config.dependencies.partR[0]).to.equal('partC') - expect(pattern.config.dependencies.partR[1]).to.equal('partA') - // Inject - expect(pattern.config.inject.partB).to.equal('partA') - expect(pattern.config.inject.partC).to.equal('partB') - expect(pattern.config.inject.partR).to.equal('partA') - // Draft order - expect(pattern.config.draftOrder[0]).to.equal('partA') - expect(pattern.config.draftOrder[1]).to.equal('partB') - expect(pattern.config.draftOrder[2]).to.equal('partC') - expect(pattern.config.draftOrder[3]).to.equal('partR') - // Points - expect(pattern.parts.partA.points.a1.x).to.equal(1) - expect(pattern.parts.partA.points.a1.y).to.equal(1) - expect(pattern.parts.partA.points.a2.x).to.equal(11) - expect(pattern.parts.partA.points.a2.y).to.equal(11) - expect(pattern.parts.partB.points.b1.x).to.equal(2) - expect(pattern.parts.partB.points.b1.y).to.equal(2) - expect(pattern.parts.partB.points.b2.x).to.equal(22) - expect(pattern.parts.partB.points.b2.y).to.equal(22) - expect(pattern.parts.partC.points.c1.x).to.equal(3) - expect(pattern.parts.partC.points.c1.y).to.equal(3) - expect(pattern.parts.partC.points.c2.x).to.equal(33) - expect(pattern.parts.partC.points.c2.y).to.equal(33) - expect(pattern.parts.partR.points.r1.x).to.equal(4) - expect(pattern.parts.partR.points.r1.y).to.equal(4) - expect(pattern.parts.partR.points.r2.x).to.equal(44) - expect(pattern.parts.partR.points.r2.y).to.equal(44) - // Paths in partA - expect(pattern.parts.partA.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partA.paths.a.ops[1].to.y).to.equal(11) - // Paths in partB - expect(pattern.parts.partB.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partB.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partB.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partB.paths.b.ops[1].to.y).to.equal(22) - // Paths in partC - expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partC.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partC.paths.b.ops[1].to.y).to.equal(22) - expect(pattern.parts.partC.paths.c.ops[0].to.x).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[0].to.y).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[1].to.x).to.equal(33) - expect(pattern.parts.partC.paths.c.ops[1].to.y).to.equal(33) - // Paths in partR - expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partR.paths.r.ops[0].to.x).to.equal(4) - expect(pattern.parts.partR.paths.r.ops[0].to.y).to.equal(4) - expect(pattern.parts.partR.paths.r.ops[1].to.x).to.equal(44) - expect(pattern.parts.partR.paths.r.ops[1].to.y).to.equal(44) -}) - -it("Design constructor should resolve nested dependencies (2022)", () => { - const partA = { - name: "partA", - options: { optionA: { bool: true } }, - measurements: [ 'measieA' ], - optionalMeasurements: [ 'optmeasieA' ], - draft: part => { - const { points, Point, paths, Path } = part.shorthand() - points.a1 = new Point(1,1) - points.a2 = new Point(11,11) - paths.a = new Path().move(points.a1).line(points.a2) - return part - } - } - const partB = { - name: "partB", - from: partA, - options: { optionB: { pct: 12, min: 2, max: 20 } }, - measurements: [ 'measieB' ], - optionalMeasurements: [ 'optmeasieB', 'measieA' ], - draft: part => { - const { points, Point, paths, Path } = part.shorthand() - points.b1 = new Point(2,2) - points.b2 = new Point(22,22) - paths.b = new Path().move(points.b1).line(points.b2) - return part - } - } - const partC = { - name: "partC", - from: partB, - options: { optionC: { deg: 5, min: 0, max: 15 } }, - measurements: [ 'measieC' ], - optionalMeasurements: [ 'optmeasieC', 'measieA' ], - draft: part => { - const { points, Point, paths, Path } = part.shorthand() - points.c1 = new Point(3,3) - points.c2 = new Point(33,33) - paths.c = new Path().move(points.c1).line(points.c2) - return part - } - } - const partD = { - name: "partD", - after: partC, - options: { optionD: { dflt: 'red', list: ['red', 'green', 'blue'] } }, - measurements: [ 'measieD' ], - optionalMeasurements: [ 'optmeasieD', 'measieA' ], - draft: part => { - const { points, Point, paths, Path } = part.shorthand() - points.d1 = new Point(4,4) - points.d2 = new Point(44,44) - paths.d = new Path().move(points.d1).line(points.d2) - return part - } - } - const Design = new freesewing.Design({ parts: [ partD ] }); - const pattern = new Design().draft() - // Measurements - expect(pattern.config.measurements.length).to.equal(4) - expect(pattern.config.measurements.indexOf('measieA') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieB') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieC') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieD') === -1).to.equal(false) - // Optional measurements - expect(pattern.config.optionalMeasurements.length).to.equal(4) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieA') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieB') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieC') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieD') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('measieA') === -1).to.equal(true) - // Options - expect(pattern.config.options.optionA.bool).to.equal(true) - expect(pattern.config.options.optionB.pct).to.equal(12) - expect(pattern.config.options.optionB.min).to.equal(2) - expect(pattern.config.options.optionB.max).to.equal(20) - expect(pattern.config.options.optionC.deg).to.equal(5) - expect(pattern.config.options.optionC.min).to.equal(0) - expect(pattern.config.options.optionC.max).to.equal(15) - expect(pattern.config.options.optionD.dflt).to.equal('red') - expect(pattern.config.options.optionD.list[0]).to.equal('red') - expect(pattern.config.options.optionD.list[1]).to.equal('green') - expect(pattern.config.options.optionD.list[2]).to.equal('blue') - // Dependencies - expect(pattern.config.dependencies.partB[0]).to.equal('partA') - expect(pattern.config.dependencies.partC[0]).to.equal('partB') - expect(pattern.config.dependencies.partD[0]).to.equal('partC') - // Inject - expect(pattern.config.inject.partB).to.equal('partA') - expect(pattern.config.inject.partC).to.equal('partB') - // Draft order - expect(pattern.config.draftOrder[0]).to.equal('partA') - expect(pattern.config.draftOrder[1]).to.equal('partB') - expect(pattern.config.draftOrder[2]).to.equal('partC') - expect(pattern.config.draftOrder[3]).to.equal('partD') - // Points - expect(pattern.parts.partA.points.a1.x).to.equal(1) - expect(pattern.parts.partA.points.a1.y).to.equal(1) - expect(pattern.parts.partA.points.a2.x).to.equal(11) - expect(pattern.parts.partA.points.a2.y).to.equal(11) - expect(pattern.parts.partB.points.b1.x).to.equal(2) - expect(pattern.parts.partB.points.b1.y).to.equal(2) - expect(pattern.parts.partB.points.b2.x).to.equal(22) - expect(pattern.parts.partB.points.b2.y).to.equal(22) - expect(pattern.parts.partC.points.c1.x).to.equal(3) - expect(pattern.parts.partC.points.c1.y).to.equal(3) - expect(pattern.parts.partC.points.c2.x).to.equal(33) - expect(pattern.parts.partC.points.c2.y).to.equal(33) - expect(pattern.parts.partD.points.d1.x).to.equal(4) - expect(pattern.parts.partD.points.d1.y).to.equal(4) - expect(pattern.parts.partD.points.d2.x).to.equal(44) - expect(pattern.parts.partD.points.d2.y).to.equal(44) - // Paths in partA - expect(pattern.parts.partA.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partA.paths.a.ops[1].to.y).to.equal(11) - // Paths in partB - expect(pattern.parts.partB.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partB.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partB.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partB.paths.b.ops[1].to.y).to.equal(22) - // Paths in partC - expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partC.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partC.paths.b.ops[1].to.y).to.equal(22) - expect(pattern.parts.partC.paths.c.ops[0].to.x).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[0].to.y).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[1].to.x).to.equal(33) - expect(pattern.parts.partC.paths.c.ops[1].to.y).to.equal(33) - // Paths in partR - expect(pattern.parts.partD.paths.d.ops[0].to.x).to.equal(4) - expect(pattern.parts.partD.paths.d.ops[0].to.y).to.equal(4) - expect(pattern.parts.partD.paths.d.ops[1].to.x).to.equal(44) - expect(pattern.parts.partD.paths.d.ops[1].to.y).to.equal(44) -}) -it("Pattern should merge optiongroups", () => { - const partA = { - name: "partA", - options: { optionA: { bool: true } }, - measurements: [ 'measieA' ], - optionalMeasurements: [ 'optmeasieA' ], - optionGroups: { - simple: ['simplea1', 'simplea2', 'simplea3'], - nested: { - nested1: [ 'nested1a1', 'nested1a2', 'nested1a3' ], - }, - subnested: { - subnested1: [ - 'subnested1a1', - 'subnested1a2', - 'subnested1a3', - { - subsubgroup: [ - 'subsuba1', - 'subsuba2', - { - subsubsubgroup: [ 'subsubsub1', 'simplea1' ], - } - ] - } - ] + it("Should handle a simple snapped option", () => { + const Test = new freesewing.Design({ + name: "test", + parts: ['front'], + measurements: [ 'head' ], + options: { + len: { pct: 50, min: 22, max: 78, snap: 10, ...freesewing.pctBasedOn('head') } } - }, - draft: part => part, - } - const partB = { - name: "partB", - from: partA, - options: { optionB: { pct: 12, min: 2, max: 20 } }, - measurements: [ 'measieB' ], - optionalMeasurements: [ 'optmeasieB', 'measieA' ], - optionGroups: { - simple: ['simpleb1', 'simpleb2', 'simpleb3'], - bsimple: ['bsimpleb1', 'bsimpleb2', 'bsimpleb3'], - nested: { - nested2: [ 'nested2b1', 'nested2b2', 'nested2b3' ], + }) + Test.prototype.draftFront = function(part) { + const { Point, points, Path, paths, absoluteOptions } = part.shorthand() + points.from = new Point(0, 0); + points.to = new Point( 2 * absoluteOptions.len, 0) + paths.line = new Path() + .move(points.from) + .line(points.to) + + return part + }; + let pattern = new Test({ + sample: { + type: 'option', + option: 'len' }, - subnested: { - subnested1: [ - 'subnested1b1', - 'subnested1b2', - 'subnested1b3', - { - subsubgroup: [ - 'subsubb1', - 'subsubb2', - { - subsubsubgroup: [ 'bsubsubsub1', 'simplea1' ], - } - ] - } - ] + measurements: { + head: 43.23 } - }, - draft: part => part, - } - let Design, pattern - try { - Design = new freesewing.Design({ parts: [ partB ] }); - pattern = new Design().init() - } catch(err) { - console.log(err) - } - const og = pattern.config.optionGroups - expect(og.simple.length).to.equal(6) - expect(og.simple.indexOf('simplea1') === -1).to.equal(false) - expect(og.simple.indexOf('simplea2') === -1).to.equal(false) - expect(og.simple.indexOf('simplea3') === -1).to.equal(false) - expect(og.simple.indexOf('simpleb1') === -1).to.equal(false) - expect(og.simple.indexOf('simpleb2') === -1).to.equal(false) - expect(og.simple.indexOf('simpleb3') === -1).to.equal(false) - expect(og.nested.nested1.length).to.equal(3) - expect(og.nested.nested1.indexOf('nested1a1') === -1).to.equal(false) - expect(og.nested.nested1.indexOf('nested1a2') === -1).to.equal(false) - expect(og.nested.nested1.indexOf('nested1a3') === -1).to.equal(false) - expect(og.nested.nested2.length).to.equal(3) - expect(og.nested.nested2.indexOf('nested2b1') === -1).to.equal(false) - expect(og.nested.nested2.indexOf('nested2b2') === -1).to.equal(false) - expect(og.nested.nested2.indexOf('nested2b3') === -1).to.equal(false) - expect(og.subnested.subnested1.length).to.equal(8) - expect(og.subnested.subnested1.indexOf('subnested1a1') === -1).to.equal(false) - expect(og.subnested.subnested1.indexOf('subnested1a2') === -1).to.equal(false) - expect(og.subnested.subnested1.indexOf('subnested1a3') === -1).to.equal(false) - expect(og.subnested.subnested1.indexOf('subnested1b1') === -1).to.equal(false) - expect(og.subnested.subnested1.indexOf('subnested1b2') === -1).to.equal(false) - expect(og.subnested.subnested1.indexOf('subnested1b3') === -1).to.equal(false) - // FIXME: Some work to be done still with deep-nesting of groups with the same name + }) + pattern.sample(); + expect(pattern.is).to.equal('sample') + expect(pattern.events.debug[0]).to.equal('Sampling option `len`') + expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(20); + expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(40); + expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(40); + expect(pattern.parts.front.paths.line_4.ops[1].to.x).to.equal(40); + expect(pattern.parts.front.paths.line_5.ops[1].to.x).to.equal(60); + expect(pattern.parts.front.paths.line_6.ops[1].to.x).to.equal(60); + expect(pattern.parts.front.paths.line_7.ops[1].to.x).to.equal(60); + expect(pattern.parts.front.paths.line_8.ops[1].to.x).to.equal(60); + expect(pattern.parts.front.paths.line_9.ops[1].to.x).to.equal(80); + expect(pattern.parts.front.paths.line_10.ops[1].to.x).to.equal(80); + }); + + it("Should handle a list snapped option", () => { + const Test = new freesewing.Design({ + name: "test", + parts: [ + { + name: 'front', + draft: function(part) { + const { Point, points, Path, paths, absoluteOptions } = part.shorthand() + points.from = new Point(0, 0); + points.to = new Point( absoluteOptions.len, 0) + paths.line = new Path() + .move(points.from) + .line(points.to) + + return part + } + } + ], + measurements: [ 'head' ], + options: { + len: { pct: 50, min: 22, max: 78, snap: [10,14,19,28], ...freesewing.pctBasedOn('head') } + } + }) + let pattern = new Test({ + sample: { + type: 'option', + option: 'len' + }, + measurements: { + head: 43.23 + } + }) + pattern.sample(); + expect(pattern.is).to.equal('sample') + expect(pattern.events.debug[0]).to.equal('Sampling option `len`') + expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(10); + expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(14); + expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(14); + expect(pattern.parts.front.paths.line_4.ops[1].to.x).to.equal(19); + expect(pattern.parts.front.paths.line_5.ops[1].to.x).to.equal(19); + expect(pattern.parts.front.paths.line_6.ops[1].to.x).to.equal(19); + expect(pattern.parts.front.paths.line_7.ops[1].to.x).to.equal(28); + expect(pattern.parts.front.paths.line_8.ops[1].to.x).to.equal(28); + expect(pattern.parts.front.paths.line_9.ops[1].to.x).to.equal(28); + expect(freesewing.utils.round(pattern.parts.front.paths.line_10.ops[1].to.x)).to.equal(33.72); + }); + + + it("Should retrieve the cutList", () => { + const Test = new freesewing.Design({ + name: "test", + parts: [{ + name: 'front', + draft: function(part) { + const { addCut } = part.shorthand() + addCut(4, 'lining', true) + return part + } + }], + }) + const pattern = new Test() + expect(JSON.stringify(pattern.getCutList())).to.equal(JSON.stringify({})) + pattern.draft() + const list = `{"front":{"grain":90,"materials":{"lining":{"cut":4,"identical":true}}}}` + expect(JSON.stringify(pattern.getCutList())).to.equal(list) + }); + + // 2022 style part inheritance + // I am aware this does too much for one unit test, but this is to simplify TDD + // we can split it up later + it("Design constructor should resolve nested injections", () => { + const partA = { + name: "partA", + options: { optionA: { bool: true } }, + measurements: [ 'measieA' ], + optionalMeasurements: [ 'optmeasieA' ], + draft: part => { + const { points, Point, paths, Path } = part.shorthand() + points.a1 = new Point(1,1) + points.a2 = new Point(11,11) + paths.a = new Path().move(points.a1).line(points.a2) + return part + } + } + const partB = { + name: "partB", + from: partA, + options: { optionB: { pct: 12, min: 2, max: 20 } }, + measurements: [ 'measieB' ], + optionalMeasurements: [ 'optmeasieB', 'measieA' ], + draft: part => { + const { points, Point, paths, Path } = part.shorthand() + points.b1 = new Point(2,2) + points.b2 = new Point(22,22) + paths.b = new Path().move(points.b1).line(points.b2) + return part + } + } + const partC = { + name: "partC", + from: partB, + options: { optionC: { deg: 5, min: 0, max: 15 } }, + measurements: [ 'measieC' ], + optionalMeasurements: [ 'optmeasieC', 'measieA' ], + draft: part => { + const { points, Point, paths, Path } = part.shorthand() + points.c1 = new Point(3,3) + points.c2 = new Point(33,33) + paths.c = new Path().move(points.c1).line(points.c2) + return part + } + } + const partR = { // R for runtime, which is when this wil be attached + name: "partR", + from: partA, + after: partC, + options: { optionR: { dflt: 'red', list: ['red', 'green', 'blue'] } }, + measurements: [ 'measieR' ], + optionalMeasurements: [ 'optmeasieR', 'measieA' ], + draft: part => { + const { points, Point, paths, Path } = part.shorthand() + points.r1 = new Point(4,4) + points.r2 = new Point(44,44) + paths.r = new Path().move(points.r1).line(points.r2) + return part + } + } + + const Design = new freesewing.Design({ parts: [ partC ] }); + const pattern = new Design().addPart(partR).draft() + // Measurements + expect(pattern.config.measurements.length).to.equal(4) + expect(pattern.config.measurements.indexOf('measieA') === -1).to.equal(false) + expect(pattern.config.measurements.indexOf('measieB') === -1).to.equal(false) + expect(pattern.config.measurements.indexOf('measieC') === -1).to.equal(false) + expect(pattern.config.measurements.indexOf('measieR') === -1).to.equal(false) + // Optional measurements + expect(pattern.config.optionalMeasurements.length).to.equal(4) + expect(pattern.config.optionalMeasurements.indexOf('optmeasieA') === -1).to.equal(false) + expect(pattern.config.optionalMeasurements.indexOf('optmeasieB') === -1).to.equal(false) + expect(pattern.config.optionalMeasurements.indexOf('optmeasieC') === -1).to.equal(false) + expect(pattern.config.optionalMeasurements.indexOf('optmeasieR') === -1).to.equal(false) + expect(pattern.config.optionalMeasurements.indexOf('measieA') === -1).to.equal(true) + // Options + expect(pattern.config.options.optionA.bool).to.equal(true) + expect(pattern.config.options.optionB.pct).to.equal(12) + expect(pattern.config.options.optionB.min).to.equal(2) + expect(pattern.config.options.optionB.max).to.equal(20) + expect(pattern.config.options.optionC.deg).to.equal(5) + expect(pattern.config.options.optionC.min).to.equal(0) + expect(pattern.config.options.optionC.max).to.equal(15) + expect(pattern.config.options.optionR.dflt).to.equal('red') + expect(pattern.config.options.optionR.list[0]).to.equal('red') + expect(pattern.config.options.optionR.list[1]).to.equal('green') + expect(pattern.config.options.optionR.list[2]).to.equal('blue') + // Dependencies + expect(pattern.config.dependencies.partB[0]).to.equal('partA') + expect(pattern.config.dependencies.partC[0]).to.equal('partB') + expect(pattern.config.dependencies.partR[0]).to.equal('partC') + expect(pattern.config.dependencies.partR[1]).to.equal('partA') + // Inject + expect(pattern.config.inject.partB).to.equal('partA') + expect(pattern.config.inject.partC).to.equal('partB') + expect(pattern.config.inject.partR).to.equal('partA') + // Draft order + expect(pattern.config.draftOrder[0]).to.equal('partA') + expect(pattern.config.draftOrder[1]).to.equal('partB') + expect(pattern.config.draftOrder[2]).to.equal('partC') + expect(pattern.config.draftOrder[3]).to.equal('partR') + // Points + expect(pattern.parts.partA.points.a1.x).to.equal(1) + expect(pattern.parts.partA.points.a1.y).to.equal(1) + expect(pattern.parts.partA.points.a2.x).to.equal(11) + expect(pattern.parts.partA.points.a2.y).to.equal(11) + expect(pattern.parts.partB.points.b1.x).to.equal(2) + expect(pattern.parts.partB.points.b1.y).to.equal(2) + expect(pattern.parts.partB.points.b2.x).to.equal(22) + expect(pattern.parts.partB.points.b2.y).to.equal(22) + expect(pattern.parts.partC.points.c1.x).to.equal(3) + expect(pattern.parts.partC.points.c1.y).to.equal(3) + expect(pattern.parts.partC.points.c2.x).to.equal(33) + expect(pattern.parts.partC.points.c2.y).to.equal(33) + expect(pattern.parts.partR.points.r1.x).to.equal(4) + expect(pattern.parts.partR.points.r1.y).to.equal(4) + expect(pattern.parts.partR.points.r2.x).to.equal(44) + expect(pattern.parts.partR.points.r2.y).to.equal(44) + // Paths in partA + expect(pattern.parts.partA.paths.a.ops[0].to.x).to.equal(1) + expect(pattern.parts.partA.paths.a.ops[0].to.y).to.equal(1) + expect(pattern.parts.partA.paths.a.ops[1].to.x).to.equal(11) + expect(pattern.parts.partA.paths.a.ops[1].to.y).to.equal(11) + // Paths in partB + expect(pattern.parts.partB.paths.a.ops[0].to.x).to.equal(1) + expect(pattern.parts.partB.paths.a.ops[0].to.y).to.equal(1) + expect(pattern.parts.partB.paths.a.ops[1].to.x).to.equal(11) + expect(pattern.parts.partB.paths.a.ops[1].to.y).to.equal(11) + expect(pattern.parts.partB.paths.b.ops[0].to.x).to.equal(2) + expect(pattern.parts.partB.paths.b.ops[0].to.y).to.equal(2) + expect(pattern.parts.partB.paths.b.ops[1].to.x).to.equal(22) + expect(pattern.parts.partB.paths.b.ops[1].to.y).to.equal(22) + // Paths in partC + expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) + expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) + expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) + expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) + expect(pattern.parts.partC.paths.b.ops[0].to.x).to.equal(2) + expect(pattern.parts.partC.paths.b.ops[0].to.y).to.equal(2) + expect(pattern.parts.partC.paths.b.ops[1].to.x).to.equal(22) + expect(pattern.parts.partC.paths.b.ops[1].to.y).to.equal(22) + expect(pattern.parts.partC.paths.c.ops[0].to.x).to.equal(3) + expect(pattern.parts.partC.paths.c.ops[0].to.y).to.equal(3) + expect(pattern.parts.partC.paths.c.ops[1].to.x).to.equal(33) + expect(pattern.parts.partC.paths.c.ops[1].to.y).to.equal(33) + // Paths in partR + expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) + expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) + expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) + expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) + expect(pattern.parts.partR.paths.r.ops[0].to.x).to.equal(4) + expect(pattern.parts.partR.paths.r.ops[0].to.y).to.equal(4) + expect(pattern.parts.partR.paths.r.ops[1].to.x).to.equal(44) + expect(pattern.parts.partR.paths.r.ops[1].to.y).to.equal(44) + }) + + it("Design constructor should resolve nested dependencies (2022)", () => { + const partA = { + name: "partA", + options: { optionA: { bool: true } }, + measurements: [ 'measieA' ], + optionalMeasurements: [ 'optmeasieA' ], + draft: part => { + const { points, Point, paths, Path } = part.shorthand() + points.a1 = new Point(1,1) + points.a2 = new Point(11,11) + paths.a = new Path().move(points.a1).line(points.a2) + return part + } + } + const partB = { + name: "partB", + from: partA, + options: { optionB: { pct: 12, min: 2, max: 20 } }, + measurements: [ 'measieB' ], + optionalMeasurements: [ 'optmeasieB', 'measieA' ], + draft: part => { + const { points, Point, paths, Path } = part.shorthand() + points.b1 = new Point(2,2) + points.b2 = new Point(22,22) + paths.b = new Path().move(points.b1).line(points.b2) + return part + } + } + const partC = { + name: "partC", + from: partB, + options: { optionC: { deg: 5, min: 0, max: 15 } }, + measurements: [ 'measieC' ], + optionalMeasurements: [ 'optmeasieC', 'measieA' ], + draft: part => { + const { points, Point, paths, Path } = part.shorthand() + points.c1 = new Point(3,3) + points.c2 = new Point(33,33) + paths.c = new Path().move(points.c1).line(points.c2) + return part + } + } + const partD = { + name: "partD", + after: partC, + options: { optionD: { dflt: 'red', list: ['red', 'green', 'blue'] } }, + measurements: [ 'measieD' ], + optionalMeasurements: [ 'optmeasieD', 'measieA' ], + draft: part => { + const { points, Point, paths, Path } = part.shorthand() + points.d1 = new Point(4,4) + points.d2 = new Point(44,44) + paths.d = new Path().move(points.d1).line(points.d2) + return part + } + } + const Design = new freesewing.Design({ parts: [ partD ] }); + const pattern = new Design().draft() + // Measurements + expect(pattern.config.measurements.length).to.equal(4) + expect(pattern.config.measurements.indexOf('measieA') === -1).to.equal(false) + expect(pattern.config.measurements.indexOf('measieB') === -1).to.equal(false) + expect(pattern.config.measurements.indexOf('measieC') === -1).to.equal(false) + expect(pattern.config.measurements.indexOf('measieD') === -1).to.equal(false) + // Optional measurements + expect(pattern.config.optionalMeasurements.length).to.equal(4) + expect(pattern.config.optionalMeasurements.indexOf('optmeasieA') === -1).to.equal(false) + expect(pattern.config.optionalMeasurements.indexOf('optmeasieB') === -1).to.equal(false) + expect(pattern.config.optionalMeasurements.indexOf('optmeasieC') === -1).to.equal(false) + expect(pattern.config.optionalMeasurements.indexOf('optmeasieD') === -1).to.equal(false) + expect(pattern.config.optionalMeasurements.indexOf('measieA') === -1).to.equal(true) + // Options + expect(pattern.config.options.optionA.bool).to.equal(true) + expect(pattern.config.options.optionB.pct).to.equal(12) + expect(pattern.config.options.optionB.min).to.equal(2) + expect(pattern.config.options.optionB.max).to.equal(20) + expect(pattern.config.options.optionC.deg).to.equal(5) + expect(pattern.config.options.optionC.min).to.equal(0) + expect(pattern.config.options.optionC.max).to.equal(15) + expect(pattern.config.options.optionD.dflt).to.equal('red') + expect(pattern.config.options.optionD.list[0]).to.equal('red') + expect(pattern.config.options.optionD.list[1]).to.equal('green') + expect(pattern.config.options.optionD.list[2]).to.equal('blue') + // Dependencies + expect(pattern.config.dependencies.partB[0]).to.equal('partA') + expect(pattern.config.dependencies.partC[0]).to.equal('partB') + expect(pattern.config.dependencies.partD[0]).to.equal('partC') + // Inject + expect(pattern.config.inject.partB).to.equal('partA') + expect(pattern.config.inject.partC).to.equal('partB') + // Draft order + expect(pattern.config.draftOrder[0]).to.equal('partA') + expect(pattern.config.draftOrder[1]).to.equal('partB') + expect(pattern.config.draftOrder[2]).to.equal('partC') + expect(pattern.config.draftOrder[3]).to.equal('partD') + // Points + expect(pattern.parts.partA.points.a1.x).to.equal(1) + expect(pattern.parts.partA.points.a1.y).to.equal(1) + expect(pattern.parts.partA.points.a2.x).to.equal(11) + expect(pattern.parts.partA.points.a2.y).to.equal(11) + expect(pattern.parts.partB.points.b1.x).to.equal(2) + expect(pattern.parts.partB.points.b1.y).to.equal(2) + expect(pattern.parts.partB.points.b2.x).to.equal(22) + expect(pattern.parts.partB.points.b2.y).to.equal(22) + expect(pattern.parts.partC.points.c1.x).to.equal(3) + expect(pattern.parts.partC.points.c1.y).to.equal(3) + expect(pattern.parts.partC.points.c2.x).to.equal(33) + expect(pattern.parts.partC.points.c2.y).to.equal(33) + expect(pattern.parts.partD.points.d1.x).to.equal(4) + expect(pattern.parts.partD.points.d1.y).to.equal(4) + expect(pattern.parts.partD.points.d2.x).to.equal(44) + expect(pattern.parts.partD.points.d2.y).to.equal(44) + // Paths in partA + expect(pattern.parts.partA.paths.a.ops[0].to.x).to.equal(1) + expect(pattern.parts.partA.paths.a.ops[0].to.y).to.equal(1) + expect(pattern.parts.partA.paths.a.ops[1].to.x).to.equal(11) + expect(pattern.parts.partA.paths.a.ops[1].to.y).to.equal(11) + // Paths in partB + expect(pattern.parts.partB.paths.a.ops[0].to.x).to.equal(1) + expect(pattern.parts.partB.paths.a.ops[0].to.y).to.equal(1) + expect(pattern.parts.partB.paths.a.ops[1].to.x).to.equal(11) + expect(pattern.parts.partB.paths.a.ops[1].to.y).to.equal(11) + expect(pattern.parts.partB.paths.b.ops[0].to.x).to.equal(2) + expect(pattern.parts.partB.paths.b.ops[0].to.y).to.equal(2) + expect(pattern.parts.partB.paths.b.ops[1].to.x).to.equal(22) + expect(pattern.parts.partB.paths.b.ops[1].to.y).to.equal(22) + // Paths in partC + expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) + expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) + expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) + expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) + expect(pattern.parts.partC.paths.b.ops[0].to.x).to.equal(2) + expect(pattern.parts.partC.paths.b.ops[0].to.y).to.equal(2) + expect(pattern.parts.partC.paths.b.ops[1].to.x).to.equal(22) + expect(pattern.parts.partC.paths.b.ops[1].to.y).to.equal(22) + expect(pattern.parts.partC.paths.c.ops[0].to.x).to.equal(3) + expect(pattern.parts.partC.paths.c.ops[0].to.y).to.equal(3) + expect(pattern.parts.partC.paths.c.ops[1].to.x).to.equal(33) + expect(pattern.parts.partC.paths.c.ops[1].to.y).to.equal(33) + // Paths in partR + expect(pattern.parts.partD.paths.d.ops[0].to.x).to.equal(4) + expect(pattern.parts.partD.paths.d.ops[0].to.y).to.equal(4) + expect(pattern.parts.partD.paths.d.ops[1].to.x).to.equal(44) + expect(pattern.parts.partD.paths.d.ops[1].to.y).to.equal(44) + }) + it("Pattern should merge optiongroups", () => { + const partA = { + name: "partA", + options: { optionA: { bool: true } }, + measurements: [ 'measieA' ], + optionalMeasurements: [ 'optmeasieA' ], + optionGroups: { + simple: ['simplea1', 'simplea2', 'simplea3'], + nested: { + nested1: [ 'nested1a1', 'nested1a2', 'nested1a3' ], + }, + subnested: { + subnested1: [ + 'subnested1a1', + 'subnested1a2', + 'subnested1a3', + { + subsubgroup: [ + 'subsuba1', + 'subsuba2', + { + subsubsubgroup: [ 'subsubsub1', 'simplea1' ], + } + ] + } + ] + } + }, + draft: part => part, + } + const partB = { + name: "partB", + from: partA, + options: { optionB: { pct: 12, min: 2, max: 20 } }, + measurements: [ 'measieB' ], + optionalMeasurements: [ 'optmeasieB', 'measieA' ], + optionGroups: { + simple: ['simpleb1', 'simpleb2', 'simpleb3'], + bsimple: ['bsimpleb1', 'bsimpleb2', 'bsimpleb3'], + nested: { + nested2: [ 'nested2b1', 'nested2b2', 'nested2b3' ], + }, + subnested: { + subnested1: [ + 'subnested1b1', + 'subnested1b2', + 'subnested1b3', + { + subsubgroup: [ + 'subsubb1', + 'subsubb2', + { + subsubsubgroup: [ 'bsubsubsub1', 'simplea1' ], + } + ] + } + ] + } + }, + draft: part => part, + } + let Design, pattern + try { + Design = new freesewing.Design({ parts: [ partB ] }); + pattern = new Design().init() + } catch(err) { + console.log(err) + } + const og = pattern.config.optionGroups + expect(og.simple.length).to.equal(6) + expect(og.simple.indexOf('simplea1') === -1).to.equal(false) + expect(og.simple.indexOf('simplea2') === -1).to.equal(false) + expect(og.simple.indexOf('simplea3') === -1).to.equal(false) + expect(og.simple.indexOf('simpleb1') === -1).to.equal(false) + expect(og.simple.indexOf('simpleb2') === -1).to.equal(false) + expect(og.simple.indexOf('simpleb3') === -1).to.equal(false) + expect(og.nested.nested1.length).to.equal(3) + expect(og.nested.nested1.indexOf('nested1a1') === -1).to.equal(false) + expect(og.nested.nested1.indexOf('nested1a2') === -1).to.equal(false) + expect(og.nested.nested1.indexOf('nested1a3') === -1).to.equal(false) + expect(og.nested.nested2.length).to.equal(3) + expect(og.nested.nested2.indexOf('nested2b1') === -1).to.equal(false) + expect(og.nested.nested2.indexOf('nested2b2') === -1).to.equal(false) + expect(og.nested.nested2.indexOf('nested2b3') === -1).to.equal(false) + expect(og.subnested.subnested1.length).to.equal(8) + expect(og.subnested.subnested1.indexOf('subnested1a1') === -1).to.equal(false) + expect(og.subnested.subnested1.indexOf('subnested1a2') === -1).to.equal(false) + expect(og.subnested.subnested1.indexOf('subnested1a3') === -1).to.equal(false) + expect(og.subnested.subnested1.indexOf('subnested1b1') === -1).to.equal(false) + expect(og.subnested.subnested1.indexOf('subnested1b2') === -1).to.equal(false) + expect(og.subnested.subnested1.indexOf('subnested1b3') === -1).to.equal(false) + // FIXME: Some work to be done still with deep-nesting of groups with the same name + }) }) diff --git a/packages/core/tests/point.test.mjs b/packages/core/tests/point.test.mjs index fddc72c138d..3deb0640c0c 100644 --- a/packages/core/tests/point.test.mjs +++ b/packages/core/tests/point.test.mjs @@ -5,496 +5,498 @@ const expect = chai.expect const Point = freesewing.Point const round = freesewing.utils.round -it("Should return point object", () => { - let result = new Point(2, 4); - expect(result).to.be.a("object"); - expect(result.x).to.equal(2); - expect(result.y).to.equal(4); -}); - -it("Should not limit point precision", () => { - let result = new Point(2.12345, 4.98765); - expect(result.x).to.equal(2.12345); - expect(result.y).to.equal(4.98765); -}); - -it("Should return distance", () => { - expect(round(new Point(2, 4).dist(new Point(-123, -32423)))).to.equal(32427.24); -}); - -it("Should return slope", () => { - let from = new Point(0, 0); - expect(from.slope(new Point(0, -10))).to.equal(-Infinity); - expect(from.slope(new Point(10, 0))).to.equal(0); - expect(from.slope(new Point(0, 10))).to.equal(Infinity); - expect(from.slope(new Point(-10, 0))).to.equal(-0); - expect(from.slope(new Point(10, 10))).to.equal(1); - expect(from.slope(new Point(-10, 5))).to.equal(-0.5); -}); - -it("Should return angle", () => { - let from = new Point(0, 0); - expect(from.angle(new Point(10, 0))).to.equal(0); - expect(from.angle(new Point(-20, 0))).to.equal(180); - expect(from.angle(new Point(0, -10))).to.equal(90); - expect(from.angle(new Point(0, 10))).to.equal(270); - expect(from.angle(new Point(10, -10))).to.equal(45); - expect(from.angle(new Point(10, 10))).to.equal(315); -}); - -it("Should copy a point", () => { - let result = new Point(2, 4).copy(); - expect(result.x).to.equal(2); - expect(result.y).to.equal(4); -}); - -it("Should check points for equality", () => { - let a = new Point(-123, 456); - let b = new Point(-123, 456); - expect(a).to.deep.equal(b); -}); - -it("Should flip point around unset X value", () => { - let result = new Point(2, 4).flipX(); - expect(result.x).to.equal(-2); - expect(result.y).to.equal(4); -}); - -it("Should flip point around X value that is zero", () => { - let flip = new Point(0, 0); - let result = new Point(2, 4).flipX(flip); - expect(result.x).to.equal(-2); - expect(result.y).to.equal(4); -}); - -it("Should flip point around X value", () => { - let result = new Point(2, 4).flipX(new Point(-20, 19)); - expect(result.x).to.equal(-42); - expect(result.y).to.equal(4); -}); - -it("Should flip point around unset Y value", () => { - let result = new Point(2, 4).flipY(); - expect(result.x).to.equal(2); - expect(result.y).to.equal(-4); -}); - -it("Should flip point around Y value that is zero", () => { - let flip = new Point(0, 0); - let result = new Point(2, 4).flipY(flip); - expect(result.x).to.equal(2); - expect(result.y).to.equal(-4); -}); - -it("Should flip point around Y value", () => { - let result = new Point(2, 4).flipY(new Point(12, -14)); - expect(result.x).to.equal(2); - expect(result.y).to.equal(-32); -}); - -it("Should shift a point", () => { - let origin = new Point(0, 0); - let n = origin.shift(90, 10); - let e = origin.shift(0, 10); - let s = origin.shift(270, 10); - let w = origin.shift(180, 10); - expect(round(n.x)).to.equal(0); - expect(round(n.y)).to.equal(-10); - expect(round(e.x)).to.equal(10); - expect(round(e.y)).to.equal(0); - expect(round(s.x)).to.equal(0); - expect(round(s.y)).to.equal(10); - expect(round(w.x)).to.equal(-10); - expect(round(w.y)).to.equal(0); - let rand = origin.shift(-123, 456); - expect(round(rand.x)).to.equal(-248.36); - expect(round(rand.y)).to.equal(382.43); -}); - -it("Should shift a point towards another", () => { - let origin = new Point(0, 0); - let n = new Point(0, -10); - let e = new Point(10, 0); - let s = new Point(0, 10); - let w = new Point(-10, 0); - let sn = origin.shiftTowards(n, 123); - let se = origin.shiftTowards(e, 123); - let ss = origin.shiftTowards(s, 123); - let sw = origin.shiftTowards(w, 123); - expect(round(sn.x)).to.equal(0); - expect(round(sn.y)).to.equal(-123); - expect(round(se.x)).to.equal(123); - expect(round(se.y)).to.equal(0); - expect(round(ss.x)).to.equal(0); - expect(round(ss.y)).to.equal(123); - expect(round(sw.x)).to.equal(-123); - expect(round(sw.y)).to.equal(0); - expect(round(sw.shiftTowards(sn, 100).x)).to.equal(-52.29); - expect(round(ss.shiftTowards(se, 200).y)).to.equal(-18.42); -}); - -it("Should shift a point a fraction towards another", () => { - let origin = new Point(0, 0); - let n = new Point(0, -10); - let e = new Point(10, 0); - let s = new Point(0, 10); - let w = new Point(-10, 0); - let sn = origin.shiftFractionTowards(n, 1.5); - let se = origin.shiftFractionTowards(e, 1.5); - let ss = origin.shiftFractionTowards(s, 0.5); - let sw = origin.shiftFractionTowards(w, 2.5); - expect(round(sn.x)).to.equal(0); - expect(round(sn.y)).to.equal(-15); - expect(round(se.x)).to.equal(15); - expect(round(se.y)).to.equal(0); - expect(round(ss.x)).to.equal(0); - expect(round(ss.y)).to.equal(5); - expect(round(sw.x)).to.equal(-25); - expect(round(sw.y)).to.equal(0); - expect(round(sw.shiftFractionTowards(sn, 100).x)).to.equal(2475); - expect(round(ss.shiftFractionTowards(se, 200).y)).to.equal(-995); -}); - -it("Should shift a point beyond another", () => { - let origin = new Point(0, 0); - let n = new Point(0, -10); - let e = new Point(10, 0); - let s = new Point(0, 10); - let w = new Point(-10, 0); - let sn = origin.shiftOutwards(n, 100); - let se = origin.shiftOutwards(e, 100); - let ss = origin.shiftOutwards(s, 100); - let sw = origin.shiftOutwards(w, 100); - expect(round(sn.x)).to.equal(0); - expect(round(sn.y)).to.equal(-110); - expect(round(se.x)).to.equal(110); - expect(round(se.y)).to.equal(0); - expect(round(ss.x)).to.equal(0); - expect(round(ss.y)).to.equal(110); - expect(round(sw.x)).to.equal(-110); - expect(round(sw.y)).to.equal(0); - expect(round(sw.shiftOutwards(sn, 100).x)).to.equal(70.71); - expect(round(ss.shiftOutwards(se, 200).y)).to.equal(-141.42); -}); - -it("Should rotate a point around another", () => { - let sun = new Point(0, 0); - let moon = new Point(10, 0); - let a = moon.rotate(90, sun); - expect(round(a.x)).to.equal(0); - expect(round(a.y)).to.equal(-10); - let b = moon.rotate(-90, sun); - expect(round(b.x)).to.equal(0); - expect(round(b.y)).to.equal(10); - let c = moon.rotate(180, sun); - expect(round(c.x)).to.equal(-10); - expect(round(c.y)).to.equal(0); - let sun2 = new Point(222, 44); - let moon2 = new Point(212, 41); - let d = moon2.rotate(90, sun2); - expect(round(d.x)).to.equal(219); - expect(round(d.y)).to.equal(54); -}); - -it("Should set an attribute", () => { - let p = new Point(0, 0).attr("class", "test"); - expect(p.attributes.get("class")).to.equal("test"); - p.attr("class", "more"); - expect(p.attributes.get("class")).to.equal("test more"); - p.attr("class", "less", true); - expect(p.attributes.get("class")).to.equal("less"); -}); - -it("Should detect points in the same location", () => { - let p1 = new Point(123, 456); - let p2 = new Point(123, 456); - expect(p1.sitsOn(p2)).to.equal(true); - p2.x = 122.99; - expect(p1.sitsOn(p2)).to.equal(false); -}); - -it("Should clone a point", () => { - let p1 = new Point(123, 456).attr("class", "something"); - p1.attr("class", "else"); - let p2 = p1.clone(); - expect(p2.sitsOn(p1)).to.equal(true); - expect(p2.attributes.get("class")).to.equal("something else"); -}); - -it("Should translate a point", () => { - let p1 = new Point(10, 20); - let p2 = p1.translate(15, 50); - expect(p2.x).to.equal(25); - expect(p2.y).to.equal(70); -}); - -it("Should add raise methods to a point", () => { - const raise = () => 'hello' - const p1 = new Point(10, 20).withRaise(raise); - expect(p1.raise()).to.equal('hello'); -}); - -it("Should raise a warning on invalid point coordinates", () => { - const invalid = { x: false, y: false } - const raiseX = { warning: () => invalid.x = true } - const raiseY = { warning: () => invalid.y = true } - const p1 = new Point('a',10).withRaise(raiseX); - const p2 = new Point(20, 'b').withRaise(raiseY); - expect(invalid.x).to.equal(false); - expect(invalid.y).to.equal(false); - p1.check() - p2.check() - expect(invalid.x).to.equal(true); - expect(invalid.y).to.equal(true); -}); - -it("Should raise a warning if rotation is not a number", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - const p2 = new Point(20, 20).withRaise(raise); - expect(invalid).to.equal(false); - const p3 = p1.rotate('a', p2) - expect(invalid).to.equal(true); -}); - -it("Should raise a warning if rotating around what is not a point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.rotate(45, 'a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when flipX'ing around what is not a point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - const p2 = new Point(20, 20).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.flipX('a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when flipY'ing around what is not a point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - const p2 = new Point(20, 20).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.flipY('a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when shifting with a distance that is not a number", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.shift(0, 'a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when shifting with an angle that is not a number", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.shift('a', 12) - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when shifting towards with a distance that is not a number", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - const p2 = new Point(20,20).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.shiftTowards(p2, 'a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when shifting towards with a target that is not a point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - const p2 = new Point(20,20).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.shiftTowards('a', 10) - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when shifting fraction towards with a distance that is not a number", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - const p2 = new Point(20,20).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.shiftFractionTowards(p2, 'a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when shifting a fraction towards with a target that is not a point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - const p2 = new Point(20,20).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.shiftFractionTowards('a', 0.1) - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when shifting outowards with a distance that is not a number", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - const p2 = new Point(20,20).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.shiftOutwards(p2, 'a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when shifting a outowards with a target that is not a point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - const p2 = new Point(20,20).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.shiftOutwards('a', 0.1) - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when translating with an X-delta that is not a number", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.translate('a', 10) - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when translating with an Y-delta that is not a number", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.translate(10, 'a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when sitsOn receives a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.sitsOn('a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should raise a warning when sitsRoughlyOn receives a non-point", () => { - let invalid = false - const raise = { warning: () => invalid = true } - const p1 = new Point(10,10).withRaise(raise); - expect(invalid).to.equal(false); - try { - p1.sitsRoughlyOn('a') - } - catch (err) { - expect(''+err).to.contain("check is not a function") - } - expect(invalid).to.equal(true); -}); - -it("Should set the data-text property in a chainable way", () => { - const p1 = new Point(10,10).setText('hello') - expect(p1.attributes.get('data-text')).to.equal('hello'); -}); - -it("Should set the data-text-class property in a chainable way", () => { - const p1 = new Point(10,10).setText('hello', 'fabric') - expect(p1.attributes.get('data-text')).to.equal('hello'); - expect(p1.attributes.get('data-text-class')).to.equal('fabric'); -}); - -it("Should set the data-circle property in a chainable way", () => { - const p1 = new Point(10,10).setCircle('20') - expect(p1.attributes.get('data-circle')).to.equal('20'); -}); - -it("Should set the data-circle-class property in a chainable way", () => { - const p1 = new Point(10,10).setCircle('20', 'fabric') - expect(p1.attributes.get('data-circle')).to.equal('20'); - expect(p1.attributes.get('data-circle-class')).to.equal('fabric'); +describe('Point', () => { + it("Should return point object", () => { + let result = new Point(2, 4); + expect(result).to.be.a("object"); + expect(result.x).to.equal(2); + expect(result.y).to.equal(4); + }); + + it("Should not limit point precision", () => { + let result = new Point(2.12345, 4.98765); + expect(result.x).to.equal(2.12345); + expect(result.y).to.equal(4.98765); + }); + + it("Should return distance", () => { + expect(round(new Point(2, 4).dist(new Point(-123, -32423)))).to.equal(32427.24); + }); + + it("Should return slope", () => { + let from = new Point(0, 0); + expect(from.slope(new Point(0, -10))).to.equal(-Infinity); + expect(from.slope(new Point(10, 0))).to.equal(0); + expect(from.slope(new Point(0, 10))).to.equal(Infinity); + expect(from.slope(new Point(-10, 0))).to.equal(-0); + expect(from.slope(new Point(10, 10))).to.equal(1); + expect(from.slope(new Point(-10, 5))).to.equal(-0.5); + }); + + it("Should return angle", () => { + let from = new Point(0, 0); + expect(from.angle(new Point(10, 0))).to.equal(0); + expect(from.angle(new Point(-20, 0))).to.equal(180); + expect(from.angle(new Point(0, -10))).to.equal(90); + expect(from.angle(new Point(0, 10))).to.equal(270); + expect(from.angle(new Point(10, -10))).to.equal(45); + expect(from.angle(new Point(10, 10))).to.equal(315); + }); + + it("Should copy a point", () => { + let result = new Point(2, 4).copy(); + expect(result.x).to.equal(2); + expect(result.y).to.equal(4); + }); + + it("Should check points for equality", () => { + let a = new Point(-123, 456); + let b = new Point(-123, 456); + expect(a).to.deep.equal(b); + }); + + it("Should flip point around unset X value", () => { + let result = new Point(2, 4).flipX(); + expect(result.x).to.equal(-2); + expect(result.y).to.equal(4); + }); + + it("Should flip point around X value that is zero", () => { + let flip = new Point(0, 0); + let result = new Point(2, 4).flipX(flip); + expect(result.x).to.equal(-2); + expect(result.y).to.equal(4); + }); + + it("Should flip point around X value", () => { + let result = new Point(2, 4).flipX(new Point(-20, 19)); + expect(result.x).to.equal(-42); + expect(result.y).to.equal(4); + }); + + it("Should flip point around unset Y value", () => { + let result = new Point(2, 4).flipY(); + expect(result.x).to.equal(2); + expect(result.y).to.equal(-4); + }); + + it("Should flip point around Y value that is zero", () => { + let flip = new Point(0, 0); + let result = new Point(2, 4).flipY(flip); + expect(result.x).to.equal(2); + expect(result.y).to.equal(-4); + }); + + it("Should flip point around Y value", () => { + let result = new Point(2, 4).flipY(new Point(12, -14)); + expect(result.x).to.equal(2); + expect(result.y).to.equal(-32); + }); + + it("Should shift a point", () => { + let origin = new Point(0, 0); + let n = origin.shift(90, 10); + let e = origin.shift(0, 10); + let s = origin.shift(270, 10); + let w = origin.shift(180, 10); + expect(round(n.x)).to.equal(0); + expect(round(n.y)).to.equal(-10); + expect(round(e.x)).to.equal(10); + expect(round(e.y)).to.equal(0); + expect(round(s.x)).to.equal(0); + expect(round(s.y)).to.equal(10); + expect(round(w.x)).to.equal(-10); + expect(round(w.y)).to.equal(0); + let rand = origin.shift(-123, 456); + expect(round(rand.x)).to.equal(-248.36); + expect(round(rand.y)).to.equal(382.43); + }); + + it("Should shift a point towards another", () => { + let origin = new Point(0, 0); + let n = new Point(0, -10); + let e = new Point(10, 0); + let s = new Point(0, 10); + let w = new Point(-10, 0); + let sn = origin.shiftTowards(n, 123); + let se = origin.shiftTowards(e, 123); + let ss = origin.shiftTowards(s, 123); + let sw = origin.shiftTowards(w, 123); + expect(round(sn.x)).to.equal(0); + expect(round(sn.y)).to.equal(-123); + expect(round(se.x)).to.equal(123); + expect(round(se.y)).to.equal(0); + expect(round(ss.x)).to.equal(0); + expect(round(ss.y)).to.equal(123); + expect(round(sw.x)).to.equal(-123); + expect(round(sw.y)).to.equal(0); + expect(round(sw.shiftTowards(sn, 100).x)).to.equal(-52.29); + expect(round(ss.shiftTowards(se, 200).y)).to.equal(-18.42); + }); + + it("Should shift a point a fraction towards another", () => { + let origin = new Point(0, 0); + let n = new Point(0, -10); + let e = new Point(10, 0); + let s = new Point(0, 10); + let w = new Point(-10, 0); + let sn = origin.shiftFractionTowards(n, 1.5); + let se = origin.shiftFractionTowards(e, 1.5); + let ss = origin.shiftFractionTowards(s, 0.5); + let sw = origin.shiftFractionTowards(w, 2.5); + expect(round(sn.x)).to.equal(0); + expect(round(sn.y)).to.equal(-15); + expect(round(se.x)).to.equal(15); + expect(round(se.y)).to.equal(0); + expect(round(ss.x)).to.equal(0); + expect(round(ss.y)).to.equal(5); + expect(round(sw.x)).to.equal(-25); + expect(round(sw.y)).to.equal(0); + expect(round(sw.shiftFractionTowards(sn, 100).x)).to.equal(2475); + expect(round(ss.shiftFractionTowards(se, 200).y)).to.equal(-995); + }); + + it("Should shift a point beyond another", () => { + let origin = new Point(0, 0); + let n = new Point(0, -10); + let e = new Point(10, 0); + let s = new Point(0, 10); + let w = new Point(-10, 0); + let sn = origin.shiftOutwards(n, 100); + let se = origin.shiftOutwards(e, 100); + let ss = origin.shiftOutwards(s, 100); + let sw = origin.shiftOutwards(w, 100); + expect(round(sn.x)).to.equal(0); + expect(round(sn.y)).to.equal(-110); + expect(round(se.x)).to.equal(110); + expect(round(se.y)).to.equal(0); + expect(round(ss.x)).to.equal(0); + expect(round(ss.y)).to.equal(110); + expect(round(sw.x)).to.equal(-110); + expect(round(sw.y)).to.equal(0); + expect(round(sw.shiftOutwards(sn, 100).x)).to.equal(70.71); + expect(round(ss.shiftOutwards(se, 200).y)).to.equal(-141.42); + }); + + it("Should rotate a point around another", () => { + let sun = new Point(0, 0); + let moon = new Point(10, 0); + let a = moon.rotate(90, sun); + expect(round(a.x)).to.equal(0); + expect(round(a.y)).to.equal(-10); + let b = moon.rotate(-90, sun); + expect(round(b.x)).to.equal(0); + expect(round(b.y)).to.equal(10); + let c = moon.rotate(180, sun); + expect(round(c.x)).to.equal(-10); + expect(round(c.y)).to.equal(0); + let sun2 = new Point(222, 44); + let moon2 = new Point(212, 41); + let d = moon2.rotate(90, sun2); + expect(round(d.x)).to.equal(219); + expect(round(d.y)).to.equal(54); + }); + + it("Should set an attribute", () => { + let p = new Point(0, 0).attr("class", "test"); + expect(p.attributes.get("class")).to.equal("test"); + p.attr("class", "more"); + expect(p.attributes.get("class")).to.equal("test more"); + p.attr("class", "less", true); + expect(p.attributes.get("class")).to.equal("less"); + }); + + it("Should detect points in the same location", () => { + let p1 = new Point(123, 456); + let p2 = new Point(123, 456); + expect(p1.sitsOn(p2)).to.equal(true); + p2.x = 122.99; + expect(p1.sitsOn(p2)).to.equal(false); + }); + + it("Should clone a point", () => { + let p1 = new Point(123, 456).attr("class", "something"); + p1.attr("class", "else"); + let p2 = p1.clone(); + expect(p2.sitsOn(p1)).to.equal(true); + expect(p2.attributes.get("class")).to.equal("something else"); + }); + + it("Should translate a point", () => { + let p1 = new Point(10, 20); + let p2 = p1.translate(15, 50); + expect(p2.x).to.equal(25); + expect(p2.y).to.equal(70); + }); + + it("Should add raise methods to a point", () => { + const raise = () => 'hello' + const p1 = new Point(10, 20).withRaise(raise); + expect(p1.raise()).to.equal('hello'); + }); + + it("Should raise a warning on invalid point coordinates", () => { + const invalid = { x: false, y: false } + const raiseX = { warning: () => invalid.x = true } + const raiseY = { warning: () => invalid.y = true } + const p1 = new Point('a',10).withRaise(raiseX); + const p2 = new Point(20, 'b').withRaise(raiseY); + expect(invalid.x).to.equal(false); + expect(invalid.y).to.equal(false); + p1.check() + p2.check() + expect(invalid.x).to.equal(true); + expect(invalid.y).to.equal(true); + }); + + it("Should raise a warning if rotation is not a number", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + const p2 = new Point(20, 20).withRaise(raise); + expect(invalid).to.equal(false); + const p3 = p1.rotate('a', p2) + expect(invalid).to.equal(true); + }); + + it("Should raise a warning if rotating around what is not a point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.rotate(45, 'a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when flipX'ing around what is not a point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + const p2 = new Point(20, 20).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.flipX('a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when flipY'ing around what is not a point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + const p2 = new Point(20, 20).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.flipY('a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when shifting with a distance that is not a number", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.shift(0, 'a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when shifting with an angle that is not a number", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.shift('a', 12) + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when shifting towards with a distance that is not a number", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + const p2 = new Point(20,20).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.shiftTowards(p2, 'a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when shifting towards with a target that is not a point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + const p2 = new Point(20,20).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.shiftTowards('a', 10) + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when shifting fraction towards with a distance that is not a number", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + const p2 = new Point(20,20).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.shiftFractionTowards(p2, 'a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when shifting a fraction towards with a target that is not a point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + const p2 = new Point(20,20).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.shiftFractionTowards('a', 0.1) + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when shifting outowards with a distance that is not a number", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + const p2 = new Point(20,20).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.shiftOutwards(p2, 'a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when shifting a outowards with a target that is not a point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + const p2 = new Point(20,20).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.shiftOutwards('a', 0.1) + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when translating with an X-delta that is not a number", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.translate('a', 10) + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when translating with an Y-delta that is not a number", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.translate(10, 'a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when sitsOn receives a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.sitsOn('a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should raise a warning when sitsRoughlyOn receives a non-point", () => { + let invalid = false + const raise = { warning: () => invalid = true } + const p1 = new Point(10,10).withRaise(raise); + expect(invalid).to.equal(false); + try { + p1.sitsRoughlyOn('a') + } + catch (err) { + expect(''+err).to.contain("check is not a function") + } + expect(invalid).to.equal(true); + }); + + it("Should set the data-text property in a chainable way", () => { + const p1 = new Point(10,10).setText('hello') + expect(p1.attributes.get('data-text')).to.equal('hello'); + }); + + it("Should set the data-text-class property in a chainable way", () => { + const p1 = new Point(10,10).setText('hello', 'fabric') + expect(p1.attributes.get('data-text')).to.equal('hello'); + expect(p1.attributes.get('data-text-class')).to.equal('fabric'); + }); + + it("Should set the data-circle property in a chainable way", () => { + const p1 = new Point(10,10).setCircle('20') + expect(p1.attributes.get('data-circle')).to.equal('20'); + }); + + it("Should set the data-circle-class property in a chainable way", () => { + const p1 = new Point(10,10).setCircle('20', 'fabric') + expect(p1.attributes.get('data-circle')).to.equal('20'); + expect(p1.attributes.get('data-circle-class')).to.equal('fabric'); + }); }); diff --git a/packages/core/tests/snap-proposal.mjs b/packages/core/tests/snap-proposal.mjs deleted file mode 100644 index 6c9ca5e2988..00000000000 --- a/packages/core/tests/snap-proposal.mjs +++ /dev/null @@ -1,81 +0,0 @@ -import chai from "chai" -import freesewing from "../dist/index.js" - -const expect = chai.expect - -const measurements = { head: 400 } -const toAbs = (val, { measurements }) => measurements.head * val - -it("Should snap a percentage options to equal steps", () => { - const design = new freesewing.Design({ - options: { - test: { pct: 30, min: 0, max: 100, snap: 12, toAbs } - } - }) - const patternA = new design({ options: { test: 0.13 }, measurements }) - const patternB = new design({ options: { test: 0.27 }, measurements }) - expect(patternA.settings.absoluteOptions.test).to.equal(60) - expect(patternB.settings.absoluteOptions.test).to.equal(108) -}); - -it("Should snap a percentage options to the Fibonacci sequence", () => { - const design = new freesewing.Design({ - options: { - test: { - pct: 30, min: 0, max: 100, toAbs, - snap: [ 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 ], - } - } - }) - const patternA = new design({ options: { test: 0.13 }, measurements }) - const patternB = new design({ options: { test: 0.27 }, measurements }) - const patternC = new design({ options: { test: 0.97 }, measurements }) - expect(patternA.settings.absoluteOptions.test).to.equal(55) - expect(patternB.settings.absoluteOptions.test).to.equal(89) - expect(patternC.settings.absoluteOptions.test).to.equal(388) -}); - -it("Should snap a percentage options to imperial snaps", () => { - const design = new freesewing.Design({ - options: { - test: { - pct: 30, min: 0, max: 100, toAbs, - snap: { - metric: [ 25, 50, 75, 100 ], - imperial: [ 25.4, 50.8, 76.2, 101.6 ], - } - } - } - }) - const patternA = new design({ options: { test: 0.13 }, measurements, units:'metric' }) - const patternB = new design({ options: { test: 0.27 }, measurements, units:'metric' }) - const patternC = new design({ options: { test: 0.97 }, measurements, units:'metric' }) - const patternD = new design({ options: { test: 0.01 }, measurements, units:'metric' }) - expect(patternA.settings.absoluteOptions.test).to.equal(50) - expect(patternB.settings.absoluteOptions.test).to.equal(100) - expect(patternC.settings.absoluteOptions.test).to.equal(388) - expect(patternD.settings.absoluteOptions.test).to.equal(4) -}); - -it("Should snap a percentage options to metrics snaps", () => { - const design = new freesewing.Design({ - options: { - test: { - pct: 30, min: 0, max: 100, toAbs, - snap: { - metric: [ 25, 50, 75, 100 ], - imperial: [ 25.4, 50.8, 76.2, 101.6 ], - } - } - } - }) - const patternA = new design({ options: { test: 0.13 }, measurements, units:'imperial' }) - const patternB = new design({ options: { test: 0.27 }, measurements, units:'imperial' }) - const patternC = new design({ options: { test: 0.97 }, measurements, units:'imperial' }) - const patternD = new design({ options: { test: 0.01 }, measurements, units:'imperial' }) - expect(patternA.settings.absoluteOptions.test).to.equal(50.8) - expect(patternB.settings.absoluteOptions.test).to.equal(101.6) - expect(patternC.settings.absoluteOptions.test).to.equal(388) - expect(patternD.settings.absoluteOptions.test).to.equal(4) -}); - diff --git a/packages/core/tests/snap.mjs b/packages/core/tests/snap.mjs new file mode 100644 index 00000000000..1a22941d315 --- /dev/null +++ b/packages/core/tests/snap.mjs @@ -0,0 +1,83 @@ +import chai from "chai" +import freesewing from "../dist/index.js" + +const expect = chai.expect + +const measurements = { head: 400 } +const toAbs = (val, { measurements }) => measurements.head * val + +describe('Snapped options', () => { + it("Should snap a percentage options to equal steps", () => { + const design = new freesewing.Design({ + options: { + test: { pct: 30, min: 0, max: 100, snap: 12, toAbs } + } + }) + const patternA = new design({ options: { test: 0.13 }, measurements }) + const patternB = new design({ options: { test: 0.27 }, measurements }) + expect(patternA.settings.absoluteOptions.test).to.equal(60) + expect(patternB.settings.absoluteOptions.test).to.equal(108) + }); + + it("Should snap a percentage options to the Fibonacci sequence", () => { + const design = new freesewing.Design({ + options: { + test: { + pct: 30, min: 0, max: 100, toAbs, + snap: [ 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 ], + } + } + }) + const patternA = new design({ options: { test: 0.13 }, measurements }) + const patternB = new design({ options: { test: 0.27 }, measurements }) + const patternC = new design({ options: { test: 0.97 }, measurements }) + expect(patternA.settings.absoluteOptions.test).to.equal(55) + expect(patternB.settings.absoluteOptions.test).to.equal(89) + expect(patternC.settings.absoluteOptions.test).to.equal(388) + }); + + it("Should snap a percentage options to imperial snaps", () => { + const design = new freesewing.Design({ + options: { + test: { + pct: 30, min: 0, max: 100, toAbs, + snap: { + metric: [ 25, 50, 75, 100 ], + imperial: [ 25.4, 50.8, 76.2, 101.6 ], + } + } + } + }) + const patternA = new design({ options: { test: 0.13 }, measurements, units:'metric' }) + const patternB = new design({ options: { test: 0.27 }, measurements, units:'metric' }) + const patternC = new design({ options: { test: 0.97 }, measurements, units:'metric' }) + const patternD = new design({ options: { test: 0.01 }, measurements, units:'metric' }) + expect(patternA.settings.absoluteOptions.test).to.equal(50) + expect(patternB.settings.absoluteOptions.test).to.equal(100) + expect(patternC.settings.absoluteOptions.test).to.equal(388) + expect(patternD.settings.absoluteOptions.test).to.equal(4) + }); + + it("Should snap a percentage options to metrics snaps", () => { + const design = new freesewing.Design({ + options: { + test: { + pct: 30, min: 0, max: 100, toAbs, + snap: { + metric: [ 25, 50, 75, 100 ], + imperial: [ 25.4, 50.8, 76.2, 101.6 ], + } + } + } + }) + const patternA = new design({ options: { test: 0.13 }, measurements, units:'imperial' }) + const patternB = new design({ options: { test: 0.27 }, measurements, units:'imperial' }) + const patternC = new design({ options: { test: 0.97 }, measurements, units:'imperial' }) + const patternD = new design({ options: { test: 0.01 }, measurements, units:'imperial' }) + expect(patternA.settings.absoluteOptions.test).to.equal(50.8) + expect(patternB.settings.absoluteOptions.test).to.equal(101.6) + expect(patternC.settings.absoluteOptions.test).to.equal(388) + expect(patternD.settings.absoluteOptions.test).to.equal(4) + }); +}); + diff --git a/packages/core/tests/snippet.test.mjs b/packages/core/tests/snippet.test.mjs index 5d17bdc19c7..a39c234ecde 100644 --- a/packages/core/tests/snippet.test.mjs +++ b/packages/core/tests/snippet.test.mjs @@ -3,29 +3,31 @@ import freesewing from "./dist/index.mjs" const expect = chai.expect -it("Should create a snippet", () => { - let snip1 = new freesewing.Snippet("test", new freesewing.Point(12, 34)); - expect(snip1.def).to.equal("test"); - expect(snip1.anchor.x).to.equal(12); - expect(snip1.anchor.y).to.equal(34); -}); - -it("Should clone a snippet", () => { - let snip3 = new freesewing.Snippet("boo", new freesewing.Point(56, 78)); - expect(snip3.clone().def).to.equal("boo"); - expect(snip3.clone().anchor.x).to.equal(56); - expect(snip3.clone().anchor.y).to.equal(78); -}); - -it("Should set an attribute", () => { - let s = new freesewing.Snippet("test", new freesewing.Point(12, -34)).attr( - "class", - "test" - ); - expect(s.attributes.get("class")).to.equal("test"); - s.attr("class", "more"); - expect(s.attributes.get("class")).to.equal("test more"); - s.attr("class", "less", true); - expect(s.attributes.get("class")).to.equal("less"); +describe('Snippet', () => { + it("Should create a snippet", () => { + let snip1 = new freesewing.Snippet("test", new freesewing.Point(12, 34)); + expect(snip1.def).to.equal("test"); + expect(snip1.anchor.x).to.equal(12); + expect(snip1.anchor.y).to.equal(34); + }); + + it("Should clone a snippet", () => { + let snip3 = new freesewing.Snippet("boo", new freesewing.Point(56, 78)); + expect(snip3.clone().def).to.equal("boo"); + expect(snip3.clone().anchor.x).to.equal(56); + expect(snip3.clone().anchor.y).to.equal(78); + }); + + it("Should set an attribute", () => { + let s = new freesewing.Snippet("test", new freesewing.Point(12, -34)).attr( + "class", + "test" + ); + expect(s.attributes.get("class")).to.equal("test"); + s.attr("class", "more"); + expect(s.attributes.get("class")).to.equal("test more"); + s.attr("class", "less", true); + expect(s.attributes.get("class")).to.equal("less"); + }); }); diff --git a/packages/core/tests/store.test.mjs b/packages/core/tests/store.test.mjs index 9c2ac76cca1..dc24eeab9f1 100644 --- a/packages/core/tests/store.test.mjs +++ b/packages/core/tests/store.test.mjs @@ -3,27 +3,29 @@ import freesewing from "./dist/index.mjs" const expect = chai.expect -let pattern = new freesewing.Pattern(); -let store = pattern.store; +const pattern = new freesewing.Pattern(); +const store = pattern.store; -it("Store should be a Map", () => { - expect(store.data.toString()).to.equal("[object Map]"); -}); - -it("Should set/get a store value", () => { - store.set("foo", "bar"); - expect(store.get("foo")).to.equal("bar"); -}); - -it("Should set a store value only if unset", () => { - store.setIfUnset("few", "baz"); - store.setIfUnset("few", "schmoo"); - expect(store.get("few")).to.equal("baz"); -}); - -it("Should raise a warning when retrieving a invalid key", () => { - store.get('nope') - expect(pattern.events.warning.length).to.equal(1) - expect(pattern.events.warning[0]).to.equal('Tried to access `nope` in the `store` but it is not set') +describe('Store', () => { + it("Store should be a Map", () => { + expect(store.data.toString()).to.equal("[object Map]"); + }); + + it("Should set/get a store value", () => { + store.set("foo", "bar"); + expect(store.get("foo")).to.equal("bar"); + }); + + it("Should set a store value only if unset", () => { + store.setIfUnset("few", "baz"); + store.setIfUnset("few", "schmoo"); + expect(store.get("few")).to.equal("baz"); + }); + + it("Should raise a warning when retrieving a invalid key", () => { + store.get('nope') + expect(pattern.events.warning.length).to.equal(1) + expect(pattern.events.warning[0]).to.equal('Tried to access `nope` in the `store` but it is not set') + }); }); diff --git a/packages/core/tests/svg.test.mjs b/packages/core/tests/svg.test.mjs index d652764e74d..1a52894085b 100644 --- a/packages/core/tests/svg.test.mjs +++ b/packages/core/tests/svg.test.mjs @@ -8,273 +8,275 @@ chai.use(chaiString) const expect = chai.expect const { version } = pkg -it("Svg constructor should initialize object", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - let svg = pattern.svg; - expect(svg.openGroups).to.eql([]); - expect(svg.freeId).to.equal(0); - expect(svg.body).to.equal(""); - expect(svg.style).to.equal("") - expect(svg.script).to.equal(""); - expect(svg.defs).to.equal(""); - expect(svg.pattern).to.eql(pattern); - expect(svg.prefix).to.equal( - '' - ); - expect(svg.attributes.get("xmlns")).to.equal("http://www.w3.org/2000/svg"); - expect(svg.attributes.get("xmlns:svg")).to.equal( - "http://www.w3.org/2000/svg" - ); - expect(svg.attributes.get("xmlns:xlink")).to.equal( - "http://www.w3.org/1999/xlink" - ); - expect(svg.attributes.get("xmlns:freesewing")).to.equal( - "http://freesewing.org/namespaces/freesewing" - ); - expect(svg.attributes.get("freesewing")).to.equal(version); -}); - -it("Should render Svg boilerplate", () => { - let pattern = new freesewing.Pattern(); - expect(pattern.render()).to.equalIgnoreSpaces(render.boilerplate); -}); - -it("Should render language attribute", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.locale = "nl"; - expect(pattern.render()).to.equalIgnoreSpaces(render.boilerplateNl); -}); - -it("Should render Svg boilerplate for embedding", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.embed = true; - expect(pattern.render()).to.equalIgnoreSpaces(render.embed); -}); - -it("Should render Svg part boilerplate", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - expect(pattern.render()).to.equalIgnoreSpaces(render.part); - pattern.parts.test.render = false; - expect(pattern.render()).to.equalIgnoreSpaces(render.boilerplate); -}); - -it("Should render Svg path", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.paths.test = new p.Path() - .move(new p.Point(0, 0)) - .line(new p.Point(40, 20)) - .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32)) - .close() - .attr("id", "something") - .attr("class", "freesewing"); - expect(pattern.render()).to.equalIgnoreSpaces(render.path); -}); -it("Should not render Svg path when render property is false", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.paths.test = new p.Path() - .move(new p.Point(0, 0)) - .line(new p.Point(40, 20)) - .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32)) - .close() - .attr("id", "something") - .attr("class", "freesewing"); - p.paths.test.render = false; - expect(pattern.render()).to.equalIgnoreSpaces(render.part); -}); - -it("Should render Svg text", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.points.test = new p.Point(20, 20) - .attr("data-text", "This is a test") - .attr("data-text-class", "text-lg"); - p.points.other = new p.Point(10, 10).attr("data-text", ""); - expect(pattern.render()).to.equalIgnoreSpaces(render.text); -}); - -it("Should render Svg multi-line text", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.points.test = new p.Point(20, 20) - .attr("data-text", "This is a test\nwith text on\nmultiple lines") - .attr("data-text-class", "text-lg") - .attr("data-text-lineheight", 8); - expect(pattern.render()).to.equalIgnoreSpaces(render.multiText); -}); - -it("Should render Svg multi-line text with default lineheight", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.points.test = new p.Point(20, 20) - .attr("data-text", "This is a test\nwith text on\nmultiple lines") - .attr("data-text-class", "text-lg"); - expect(pattern.render()).to.equalIgnoreSpaces(render.multiTextDflt); -}); - -it("Should not render text when there is none", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.points.test = new p.Point(20, 20); - expect(pattern.render()).to.equalIgnoreSpaces(render.part); -}); - -it("Should render Svg text on path", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.paths.test = new p.Path() - .move(new p.Point(0, 0)) - .line(new p.Point(40, 20)) - .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32)) - .close() - .attr("data-text", "This is another test") - .attr("data-text-class", "text-sm") - .attr("class", "freesewing"); - expect(pattern.render()).to.equalIgnoreSpaces(render.textOnPath); -}); - -it("Should render Svg text on path, center aligned", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.paths.test = new p.Path() - .move(new p.Point(0, 0)) - .line(new p.Point(40, 20)) - .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32)) - .close() - .attr("data-text", "This is another test") - .attr("data-text-class", "center") - .attr("class", "freesewing"); - expect(pattern.render()).to.equalIgnoreSpaces(render.textOnPathCenter); -}); - -it("Should render Svg text on path, right aligned", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.paths.test = new p.Path() - .move(new p.Point(0, 0)) - .line(new p.Point(40, 20)) - .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32)) - .close() - .attr("data-text", "This is another test") - .attr("data-text-class", "right") - .attr("class", "freesewing"); - expect(pattern.render()).to.equalIgnoreSpaces(render.textOnPathRight); -}); - -it("Should render an Svg circle", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.points.test = new p.Point(20, 20).attr("data-circle", "50"); - expect(pattern.render()).to.equalIgnoreSpaces(render.circle); -}); - -it("Should render an Svg snippet", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.snippets.test = new p.Snippet( - "test", - new p.Point(20, 20), - "This is a snippet" - ); - expect(pattern.render()).to.equalIgnoreSpaces(render.snippet); -}); - -it("Should render a rotated Svg snippet", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.snippets.test = new p.Snippet( - "test", - new p.Point(20, 20), - "This is a snippet" - ).attr('data-rotate', 90) - expect(pattern.render()).to.equalIgnoreSpaces(render.rotatedSnippet); -}); - -it("Should replaced double quotes in Svg text", () => { - const pattern = new freesewing.Pattern() - pattern.render() - expect( - pattern.svg.escapeText('This is a "test" message') - ).to.equal('This is a “test“ message') -}); - -it("Should scale an Svg snippet", () => { - let pattern = new freesewing.Pattern(); - pattern.render(); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.snippets.test = new p.Snippet( - "test", - new p.Point(20, 20), - "This is a snippet" - ).attr("data-scale", 2); - expect(pattern.render()).to.contain("scale(2)"); -}); - -it("Should run preRender hook", () => { - let pattern = new freesewing.Pattern(); - pattern.on("preRender", svg => { - svg.attributes.set("data-hook", "preRender"); +describe('Svg', () => { + it("Svg constructor should initialize object", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + let svg = pattern.svg; + expect(svg.openGroups).to.eql([]); + expect(svg.freeId).to.equal(0); + expect(svg.body).to.equal(""); + expect(svg.style).to.equal("") + expect(svg.script).to.equal(""); + expect(svg.defs).to.equal(""); + expect(svg.pattern).to.eql(pattern); + expect(svg.prefix).to.equal( + '' + ); + expect(svg.attributes.get("xmlns")).to.equal("http://www.w3.org/2000/svg"); + expect(svg.attributes.get("xmlns:svg")).to.equal( + "http://www.w3.org/2000/svg" + ); + expect(svg.attributes.get("xmlns:xlink")).to.equal( + "http://www.w3.org/1999/xlink" + ); + expect(svg.attributes.get("xmlns:freesewing")).to.equal( + "http://freesewing.org/namespaces/freesewing" + ); + expect(svg.attributes.get("freesewing")).to.equal(version); }); - pattern.render(); - expect(pattern.svg.attributes.get("data-hook")).to.equal("preRender"); -}); -it("Should run insertText hook", () => { - let pattern = new freesewing.Pattern(); - pattern.on("insertText", (locale, text) => { - return text.toUpperCase(); + it("Should render Svg boilerplate", () => { + let pattern = new freesewing.Pattern(); + expect(pattern.render()).to.equalIgnoreSpaces(render.boilerplate); }); - pattern.parts.test = new pattern.Part(); - let p = pattern.parts.test; - p.points.test = new p.Point(20, 20) - .attr("data-text", "This is a test") - .attr("data-text-class", "text-lg"); - expect(pattern.render()).to.contain("THIS IS A TEST"); -}); -it("Should run postRender hook", () => { - let pattern = new freesewing.Pattern() - pattern.on("postRender", svg => { - svg.svg = "test"; + it("Should render language attribute", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.locale = "nl"; + expect(pattern.render()).to.equalIgnoreSpaces(render.boilerplateNl); }); - expect(pattern.render()).to.equal("test"); -}); -it("Should tab in and out", () => { - let pattern = new freesewing.Pattern() - pattern.render() - const svg = pattern.svg - svg.tabs = 2 - expect(svg.tab()).to.equal(' ') + it("Should render Svg boilerplate for embedding", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.embed = true; + expect(pattern.render()).to.equalIgnoreSpaces(render.embed); + }); + + it("Should render Svg part boilerplate", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + expect(pattern.render()).to.equalIgnoreSpaces(render.part); + pattern.parts.test.render = false; + expect(pattern.render()).to.equalIgnoreSpaces(render.boilerplate); + }); + + it("Should render Svg path", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.paths.test = new p.Path() + .move(new p.Point(0, 0)) + .line(new p.Point(40, 20)) + .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32)) + .close() + .attr("id", "something") + .attr("class", "freesewing"); + expect(pattern.render()).to.equalIgnoreSpaces(render.path); + }); + it("Should not render Svg path when render property is false", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.paths.test = new p.Path() + .move(new p.Point(0, 0)) + .line(new p.Point(40, 20)) + .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32)) + .close() + .attr("id", "something") + .attr("class", "freesewing"); + p.paths.test.render = false; + expect(pattern.render()).to.equalIgnoreSpaces(render.part); + }); + + it("Should render Svg text", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.points.test = new p.Point(20, 20) + .attr("data-text", "This is a test") + .attr("data-text-class", "text-lg"); + p.points.other = new p.Point(10, 10).attr("data-text", ""); + expect(pattern.render()).to.equalIgnoreSpaces(render.text); + }); + + it("Should render Svg multi-line text", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.points.test = new p.Point(20, 20) + .attr("data-text", "This is a test\nwith text on\nmultiple lines") + .attr("data-text-class", "text-lg") + .attr("data-text-lineheight", 8); + expect(pattern.render()).to.equalIgnoreSpaces(render.multiText); + }); + + it("Should render Svg multi-line text with default lineheight", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.points.test = new p.Point(20, 20) + .attr("data-text", "This is a test\nwith text on\nmultiple lines") + .attr("data-text-class", "text-lg"); + expect(pattern.render()).to.equalIgnoreSpaces(render.multiTextDflt); + }); + + it("Should not render text when there is none", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.points.test = new p.Point(20, 20); + expect(pattern.render()).to.equalIgnoreSpaces(render.part); + }); + + it("Should render Svg text on path", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.paths.test = new p.Path() + .move(new p.Point(0, 0)) + .line(new p.Point(40, 20)) + .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32)) + .close() + .attr("data-text", "This is another test") + .attr("data-text-class", "text-sm") + .attr("class", "freesewing"); + expect(pattern.render()).to.equalIgnoreSpaces(render.textOnPath); + }); + + it("Should render Svg text on path, center aligned", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.paths.test = new p.Path() + .move(new p.Point(0, 0)) + .line(new p.Point(40, 20)) + .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32)) + .close() + .attr("data-text", "This is another test") + .attr("data-text-class", "center") + .attr("class", "freesewing"); + expect(pattern.render()).to.equalIgnoreSpaces(render.textOnPathCenter); + }); + + it("Should render Svg text on path, right aligned", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.paths.test = new p.Path() + .move(new p.Point(0, 0)) + .line(new p.Point(40, 20)) + .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32)) + .close() + .attr("data-text", "This is another test") + .attr("data-text-class", "right") + .attr("class", "freesewing"); + expect(pattern.render()).to.equalIgnoreSpaces(render.textOnPathRight); + }); + + it("Should render an Svg circle", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.points.test = new p.Point(20, 20).attr("data-circle", "50"); + expect(pattern.render()).to.equalIgnoreSpaces(render.circle); + }); + + it("Should render an Svg snippet", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.snippets.test = new p.Snippet( + "test", + new p.Point(20, 20), + "This is a snippet" + ); + expect(pattern.render()).to.equalIgnoreSpaces(render.snippet); + }); + + it("Should render a rotated Svg snippet", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.snippets.test = new p.Snippet( + "test", + new p.Point(20, 20), + "This is a snippet" + ).attr('data-rotate', 90) + expect(pattern.render()).to.equalIgnoreSpaces(render.rotatedSnippet); + }); + + it("Should replaced double quotes in Svg text", () => { + const pattern = new freesewing.Pattern() + pattern.render() + expect( + pattern.svg.escapeText('This is a "test" message') + ).to.equal('This is a “test“ message') + }); + + it("Should scale an Svg snippet", () => { + let pattern = new freesewing.Pattern(); + pattern.render(); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.snippets.test = new p.Snippet( + "test", + new p.Point(20, 20), + "This is a snippet" + ).attr("data-scale", 2); + expect(pattern.render()).to.contain("scale(2)"); + }); + + it("Should run preRender hook", () => { + let pattern = new freesewing.Pattern(); + pattern.on("preRender", svg => { + svg.attributes.set("data-hook", "preRender"); + }); + pattern.render(); + expect(pattern.svg.attributes.get("data-hook")).to.equal("preRender"); + }); + + it("Should run insertText hook", () => { + let pattern = new freesewing.Pattern(); + pattern.on("insertText", (locale, text) => { + return text.toUpperCase(); + }); + pattern.parts.test = new pattern.Part(); + let p = pattern.parts.test; + p.points.test = new p.Point(20, 20) + .attr("data-text", "This is a test") + .attr("data-text-class", "text-lg"); + expect(pattern.render()).to.contain("THIS IS A TEST"); + }); + + it("Should run postRender hook", () => { + let pattern = new freesewing.Pattern() + pattern.on("postRender", svg => { + svg.svg = "test"; + }); + expect(pattern.render()).to.equal("test"); + }); + + it("Should tab in and out", () => { + let pattern = new freesewing.Pattern() + pattern.render() + const svg = pattern.svg + svg.tabs = 2 + expect(svg.tab()).to.equal(' ') + }); }); diff --git a/packages/core/tests/utils.test.mjs b/packages/core/tests/utils.test.mjs index 063376be823..2f2d11c9dae 100644 --- a/packages/core/tests/utils.test.mjs +++ b/packages/core/tests/utils.test.mjs @@ -5,562 +5,564 @@ const { expect } = chai const utils = freesewing.utils const round = utils.round -it("Should return the correct macro name", () => { - expect(utils.macroName("test")).to.equal("_macro_test"); -}); +describe('Utils', () => { + it("Should return the correct macro name", () => { + expect(utils.macroName("test")).to.equal("_macro_test"); + }); -it("Should find the intersection of two endless line segments", () => { - let a = new freesewing.Point(10, 20); - let b = new freesewing.Point(20, 24); - let c = new freesewing.Point(90, 19); - let d = new freesewing.Point(19, 70); - let X = freesewing.utils.beamsIntersect(a, b, c, d); - expect(round(X.x)).to.equal(60.49); - expect(round(X.y)).to.equal(40.2); -}); + it("Should find the intersection of two endless line segments", () => { + let a = new freesewing.Point(10, 20); + let b = new freesewing.Point(20, 24); + let c = new freesewing.Point(90, 19); + let d = new freesewing.Point(19, 70); + let X = freesewing.utils.beamsIntersect(a, b, c, d); + expect(round(X.x)).to.equal(60.49); + expect(round(X.y)).to.equal(40.2); + }); -it("Should detect parallel lines", () => { - let a = new freesewing.Point(10, 20); - let b = new freesewing.Point(20, 20); - let c = new freesewing.Point(90, 40); - let d = new freesewing.Point(19, 40); - expect(freesewing.utils.beamsIntersect(a, b, c, d)).to.equal(false); - expect(freesewing.utils.linesIntersect(a, b, c, d)).to.equal(false); -}); + it("Should detect parallel lines", () => { + let a = new freesewing.Point(10, 20); + let b = new freesewing.Point(20, 20); + let c = new freesewing.Point(90, 40); + let d = new freesewing.Point(19, 40); + expect(freesewing.utils.beamsIntersect(a, b, c, d)).to.equal(false); + expect(freesewing.utils.linesIntersect(a, b, c, d)).to.equal(false); + }); -it("Should detect vertical lines", () => { - let a = new freesewing.Point(10, 20); - let b = new freesewing.Point(10, 90); - let c = new freesewing.Point(90, 40); - let d = new freesewing.Point(19, 40); - let X = freesewing.utils.beamsIntersect(a, b, c, d); - expect(X.x).to.equal(10); - expect(X.y).to.equal(40); - X = freesewing.utils.beamsIntersect(c, d, a, b); - expect(X.x).to.equal(10); -}); + it("Should detect vertical lines", () => { + let a = new freesewing.Point(10, 20); + let b = new freesewing.Point(10, 90); + let c = new freesewing.Point(90, 40); + let d = new freesewing.Point(19, 40); + let X = freesewing.utils.beamsIntersect(a, b, c, d); + expect(X.x).to.equal(10); + expect(X.y).to.equal(40); + X = freesewing.utils.beamsIntersect(c, d, a, b); + expect(X.x).to.equal(10); + }); -it("Should swap direction prior to finding beam intersection", () => { - let a = new freesewing.Point(10, 20); - let b = new freesewing.Point(0, 90); - let c = new freesewing.Point(90, 40); - let d = new freesewing.Point(19, 40); - let X = freesewing.utils.beamsIntersect(a, b, c, d); - expect(round(X.x)).to.equal(7.14); - expect(round(X.y)).to.equal(40); -}); + it("Should swap direction prior to finding beam intersection", () => { + let a = new freesewing.Point(10, 20); + let b = new freesewing.Point(0, 90); + let c = new freesewing.Point(90, 40); + let d = new freesewing.Point(19, 40); + let X = freesewing.utils.beamsIntersect(a, b, c, d); + expect(round(X.x)).to.equal(7.14); + expect(round(X.y)).to.equal(40); + }); -it("Should return false when two lines don't intersect", () => { - let a = new freesewing.Point(10, 20); - let b = new freesewing.Point(20, 24); - let c = new freesewing.Point(90, 19); - let d = new freesewing.Point(19, 70); - expect(freesewing.utils.linesIntersect(a, b, c, d)).to.equal(false); -}); + it("Should return false when two lines don't intersect", () => { + let a = new freesewing.Point(10, 20); + let b = new freesewing.Point(20, 24); + let c = new freesewing.Point(90, 19); + let d = new freesewing.Point(19, 70); + expect(freesewing.utils.linesIntersect(a, b, c, d)).to.equal(false); + }); -it("Should find the intersection of two line segments", () => { - let a = new freesewing.Point(10, 10); - let b = new freesewing.Point(90, 74); - let c = new freesewing.Point(90, 19); - let d = new freesewing.Point(11, 70); - let X = freesewing.utils.linesIntersect(a, b, c, d); - expect(round(X.x)).to.equal(51.95); - expect(round(X.y)).to.equal(43.56); -}); + it("Should find the intersection of two line segments", () => { + let a = new freesewing.Point(10, 10); + let b = new freesewing.Point(90, 74); + let c = new freesewing.Point(90, 19); + let d = new freesewing.Point(11, 70); + let X = freesewing.utils.linesIntersect(a, b, c, d); + expect(round(X.x)).to.equal(51.95); + expect(round(X.y)).to.equal(43.56); + }); -it("Should find the intersection of an endles line and a give X-value", () => { - let a = new freesewing.Point(10, 10); - let b = new freesewing.Point(90, 74); - let X = freesewing.utils.beamIntersectsX(a, b, 69); - expect(X.x).to.equal(69); - expect(X.y).to.equal(57.2); -}); + it("Should find the intersection of an endles line and a give X-value", () => { + let a = new freesewing.Point(10, 10); + let b = new freesewing.Point(90, 74); + let X = freesewing.utils.beamIntersectsX(a, b, 69); + expect(X.x).to.equal(69); + expect(X.y).to.equal(57.2); + }); -it("Should find the intersection of an endles line and a give Y-value", () => { - let a = new freesewing.Point(10, 10); - let b = new freesewing.Point(90, 74); - let X = freesewing.utils.beamIntersectsY(a, b, 69); - expect(X.x).to.equal(83.75); - expect(X.y).to.equal(69); -}); + it("Should find the intersection of an endles line and a give Y-value", () => { + let a = new freesewing.Point(10, 10); + let b = new freesewing.Point(90, 74); + let X = freesewing.utils.beamIntersectsY(a, b, 69); + expect(X.x).to.equal(83.75); + expect(X.y).to.equal(69); + }); -it("Should detect vertical lines never pass a give X-value", () => { - let a = new freesewing.Point(10, 10); - let b = new freesewing.Point(10, 90); - expect(freesewing.utils.beamIntersectsX(a, b, 69)).to.equal(false); -}); + it("Should detect vertical lines never pass a give X-value", () => { + let a = new freesewing.Point(10, 10); + let b = new freesewing.Point(10, 90); + expect(freesewing.utils.beamIntersectsX(a, b, 69)).to.equal(false); + }); -it("Should detect horizontal lines never pass a give Y-value", () => { - let a = new freesewing.Point(10, 10); - let b = new freesewing.Point(90, 10); - expect(freesewing.utils.beamIntersectsY(a, b, 69)).to.equal(false); -}); + it("Should detect horizontal lines never pass a give Y-value", () => { + let a = new freesewing.Point(10, 10); + let b = new freesewing.Point(90, 10); + expect(freesewing.utils.beamIntersectsY(a, b, 69)).to.equal(false); + }); -it("Should find no intersections between a curve and a line", () => { - let A = new freesewing.Point(10, 10); - let Acp = new freesewing.Point(310, 40); - let B = new freesewing.Point(110, 70); - let Bcp = new freesewing.Point(-210, 40); - let E = new freesewing.Point(-20, -20); - let D = new freesewing.Point(30, -85); + it("Should find no intersections between a curve and a line", () => { + let A = new freesewing.Point(10, 10); + let Acp = new freesewing.Point(310, 40); + let B = new freesewing.Point(110, 70); + let Bcp = new freesewing.Point(-210, 40); + let E = new freesewing.Point(-20, -20); + let D = new freesewing.Point(30, -85); - let hit = freesewing.utils.lineIntersectsCurve(E, D, A, Acp, Bcp, B); - expect(hit).to.equal(false); -}); + let hit = freesewing.utils.lineIntersectsCurve(E, D, A, Acp, Bcp, B); + expect(hit).to.equal(false); + }); -it("Should find 1 intersection between a curve and a line", () => { - let A = new freesewing.Point(10, 10); - let Acp = new freesewing.Point(310, 40); - let B = new freesewing.Point(110, 70); - let Bcp = new freesewing.Point(-210, 40); - let E = new freesewing.Point(20, 20); - let D = new freesewing.Point(30, -85); + it("Should find 1 intersection between a curve and a line", () => { + let A = new freesewing.Point(10, 10); + let Acp = new freesewing.Point(310, 40); + let B = new freesewing.Point(110, 70); + let Bcp = new freesewing.Point(-210, 40); + let E = new freesewing.Point(20, 20); + let D = new freesewing.Point(30, -85); - let hit = freesewing.utils.lineIntersectsCurve(E, D, A, Acp, Bcp, B); - expect(round(hit.x)).to.equal(20.85); - expect(round(hit.y)).to.equal(11.11); -}); + let hit = freesewing.utils.lineIntersectsCurve(E, D, A, Acp, Bcp, B); + expect(round(hit.x)).to.equal(20.85); + expect(round(hit.y)).to.equal(11.11); + }); -it("Should find 3 intersections between a curve and a line", () => { - let A = new freesewing.Point(10, 10); - let Acp = new freesewing.Point(310, 40); - let B = new freesewing.Point(110, 70); - let Bcp = new freesewing.Point(-210, 40); - let E = new freesewing.Point(20, -5); - let D = new freesewing.Point(100, 85); + it("Should find 3 intersections between a curve and a line", () => { + let A = new freesewing.Point(10, 10); + let Acp = new freesewing.Point(310, 40); + let B = new freesewing.Point(110, 70); + let Bcp = new freesewing.Point(-210, 40); + let E = new freesewing.Point(20, -5); + let D = new freesewing.Point(100, 85); - let hits = freesewing.utils.lineIntersectsCurve(E, D, A, Acp, Bcp, B); - expect(hits.length).to.equal(3); -}); + let hits = freesewing.utils.lineIntersectsCurve(E, D, A, Acp, Bcp, B); + expect(hits.length).to.equal(3); + }); -it("Should find 9 intersections between two curves", () => { - let A = new freesewing.Point(10, 10); - let Acp = new freesewing.Point(310, 40); - let B = new freesewing.Point(110, 70); - let Bcp = new freesewing.Point(-210, 40); - let C = new freesewing.Point(20, -5); - let Ccp = new freesewing.Point(60, 300); - let D = new freesewing.Point(100, 85); - let Dcp = new freesewing.Point(70, -220); + it("Should find 9 intersections between two curves", () => { + let A = new freesewing.Point(10, 10); + let Acp = new freesewing.Point(310, 40); + let B = new freesewing.Point(110, 70); + let Bcp = new freesewing.Point(-210, 40); + let C = new freesewing.Point(20, -5); + let Ccp = new freesewing.Point(60, 300); + let D = new freesewing.Point(100, 85); + let Dcp = new freesewing.Point(70, -220); - let hits = freesewing.utils.curvesIntersect(A, Acp, Bcp, B, C, Ccp, Dcp, D); - expect(hits.length).to.equal(9); -}); + let hits = freesewing.utils.curvesIntersect(A, Acp, Bcp, B, C, Ccp, Dcp, D); + expect(hits.length).to.equal(9); + }); -it("Should find 1 intersection between two curves", () => { - let A = new freesewing.Point(10, 10); - let Acp = new freesewing.Point(310, 40); - let B = new freesewing.Point(110, 70); - let Bcp = new freesewing.Point(-210, 40); - let C = new freesewing.Point(20, -5); - let Ccp = new freesewing.Point(-60, 300); - let D = new freesewing.Point(-200, 85); - let Dcp = new freesewing.Point(-270, -220); + it("Should find 1 intersection between two curves", () => { + let A = new freesewing.Point(10, 10); + let Acp = new freesewing.Point(310, 40); + let B = new freesewing.Point(110, 70); + let Bcp = new freesewing.Point(-210, 40); + let C = new freesewing.Point(20, -5); + let Ccp = new freesewing.Point(-60, 300); + let D = new freesewing.Point(-200, 85); + let Dcp = new freesewing.Point(-270, -220); - let hit = freesewing.utils.curvesIntersect(A, Acp, Bcp, B, C, Ccp, Dcp, D); - expect(round(hit.x)).to.equal(15.58); - expect(round(hit.y)).to.equal(10.56); -}); + let hit = freesewing.utils.curvesIntersect(A, Acp, Bcp, B, C, Ccp, Dcp, D); + expect(round(hit.x)).to.equal(15.58); + expect(round(hit.y)).to.equal(10.56); + }); -it("Should find no intersection between two curves", () => { - let A = new freesewing.Point(10, 10); - let Acp = new freesewing.Point(310, 40); - let B = new freesewing.Point(110, 70); - let Bcp = new freesewing.Point(-210, 40); - let C = new freesewing.Point(20, -5); - let Ccp = new freesewing.Point(-60, -300); - let D = new freesewing.Point(-200, 85); - let Dcp = new freesewing.Point(-270, -220); + it("Should find no intersection between two curves", () => { + let A = new freesewing.Point(10, 10); + let Acp = new freesewing.Point(310, 40); + let B = new freesewing.Point(110, 70); + let Bcp = new freesewing.Point(-210, 40); + let C = new freesewing.Point(20, -5); + let Ccp = new freesewing.Point(-60, -300); + let D = new freesewing.Point(-200, 85); + let Dcp = new freesewing.Point(-270, -220); - let hit = freesewing.utils.curvesIntersect(A, Acp, Bcp, B, C, Ccp, Dcp, D); - expect(hit).to.equal(false); -}); + let hit = freesewing.utils.curvesIntersect(A, Acp, Bcp, B, C, Ccp, Dcp, D); + expect(hit).to.equal(false); + }); -it("Should correctly format units", () => { - expect(freesewing.utils.units(123.456)).to.equal("12.35cm"); - expect(freesewing.utils.units(123.456, "imperial")).to.equal('4.86"'); -}); + it("Should correctly format units", () => { + expect(freesewing.utils.units(123.456)).to.equal("12.35cm"); + expect(freesewing.utils.units(123.456, "imperial")).to.equal('4.86"'); + }); -it("Should find a start or end point on beam", () => { - let A = new freesewing.Point(12, 34); - let B = new freesewing.Point(56, 78); - let checkA = new freesewing.Point(12, 34); - let checkB = new freesewing.Point(56, 78); - expect(freesewing.utils.pointOnBeam(A, B, checkA)).to.equal(true); - expect(freesewing.utils.pointOnBeam(A, B, checkB)).to.equal(true); -}); + it("Should find a start or end point on beam", () => { + let A = new freesewing.Point(12, 34); + let B = new freesewing.Point(56, 78); + let checkA = new freesewing.Point(12, 34); + let checkB = new freesewing.Point(56, 78); + expect(freesewing.utils.pointOnBeam(A, B, checkA)).to.equal(true); + expect(freesewing.utils.pointOnBeam(A, B, checkB)).to.equal(true); + }); -it("Should find whether a point lies on a line segment", () => { - let A = new freesewing.Point(12, 34); - let B = new freesewing.Point(56, 78); - let check1 = A.shiftTowards(B, 10); - let check2 = A.shiftTowards(B, 210); - expect(freesewing.utils.pointOnLine(A, B, check1)).to.equal(true); - expect(freesewing.utils.pointOnLine(A, B, check2)).to.equal(false); -}); + it("Should find whether a point lies on a line segment", () => { + let A = new freesewing.Point(12, 34); + let B = new freesewing.Point(56, 78); + let check1 = A.shiftTowards(B, 10); + let check2 = A.shiftTowards(B, 210); + expect(freesewing.utils.pointOnLine(A, B, check1)).to.equal(true); + expect(freesewing.utils.pointOnLine(A, B, check2)).to.equal(false); + }); -it("Should find a start or end point on curve", () => { - let A = new freesewing.Point(12, 34); - let Acp = new freesewing.Point(123, 4); - let B = new freesewing.Point(56, 78); - let Bcp = new freesewing.Point(5, 678); - let checkA = new freesewing.Point(12, 34); - let checkB = new freesewing.Point(56, 78); - expect(freesewing.utils.pointOnCurve(A, Acp, Bcp, B, checkA)).to.equal(true); - expect(freesewing.utils.pointOnCurve(A, Acp, Bcp, B, checkB)).to.equal(true); -}); + it("Should find a start or end point on curve", () => { + let A = new freesewing.Point(12, 34); + let Acp = new freesewing.Point(123, 4); + let B = new freesewing.Point(56, 78); + let Bcp = new freesewing.Point(5, 678); + let checkA = new freesewing.Point(12, 34); + let checkB = new freesewing.Point(56, 78); + expect(freesewing.utils.pointOnCurve(A, Acp, Bcp, B, checkA)).to.equal(true); + expect(freesewing.utils.pointOnCurve(A, Acp, Bcp, B, checkB)).to.equal(true); + }); -it("Should find the intersections of a beam and circle", () => { - let A = new freesewing.Point(45, 45).attr("data-circle", 35); - let B = new freesewing.Point(5, 50); - let C = new freesewing.Point(25, 30); - let intersections = freesewing.utils.beamIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C, - "y" - ); - expect(intersections.length).to.equal(2); - expect(round(intersections[0].x)).to.equal(45); - expect(round(intersections[0].y)).to.equal(10); - expect(round(intersections[1].x)).to.equal(10); - expect(round(intersections[1].y)).to.equal(45); -}); + it("Should find the intersections of a beam and circle", () => { + let A = new freesewing.Point(45, 45).attr("data-circle", 35); + let B = new freesewing.Point(5, 50); + let C = new freesewing.Point(25, 30); + let intersections = freesewing.utils.beamIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C, + "y" + ); + expect(intersections.length).to.equal(2); + expect(round(intersections[0].x)).to.equal(45); + expect(round(intersections[0].y)).to.equal(10); + expect(round(intersections[1].x)).to.equal(10); + expect(round(intersections[1].y)).to.equal(45); + }); -it("Should not find the intersections of this beam and circle", () => { - let A = new freesewing.Point(75, 75).attr("data-circle", 35); - let B = new freesewing.Point(5, 5); - let C = new freesewing.Point(10, 5); - let intersections = freesewing.utils.beamIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C - ); - expect(intersections).to.equal(false); -}); + it("Should not find the intersections of this beam and circle", () => { + let A = new freesewing.Point(75, 75).attr("data-circle", 35); + let B = new freesewing.Point(5, 5); + let C = new freesewing.Point(10, 5); + let intersections = freesewing.utils.beamIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C + ); + expect(intersections).to.equal(false); + }); -it("Should find one intersections between this beam and circle", () => { - let A = new freesewing.Point(5, 5).attr("data-circle", 5); - let B = new freesewing.Point(0, 0); - let C = new freesewing.Point(-10, 0); - let intersections = freesewing.utils.beamIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C - ); - expect(intersections.length).to.equal(1); - expect(intersections[0].x).to.equal(5); - expect(intersections[0].y).to.equal(0); -}); + it("Should find one intersections between this beam and circle", () => { + let A = new freesewing.Point(5, 5).attr("data-circle", 5); + let B = new freesewing.Point(0, 0); + let C = new freesewing.Point(-10, 0); + let intersections = freesewing.utils.beamIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C + ); + expect(intersections.length).to.equal(1); + expect(intersections[0].x).to.equal(5); + expect(intersections[0].y).to.equal(0); + }); -it("Should find one intersections between this tangent and circle", () => { - let A = new freesewing.Point(5, 5).attr("data-circle", 5); - let B = new freesewing.Point(0, 0); - let C = new freesewing.Point(10, 0); - let intersections = freesewing.utils.lineIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C - ); - expect(intersections.length).to.equal(1); - expect(intersections[0].x).to.equal(5); - expect(intersections[0].y).to.equal(0); -}); + it("Should find one intersections between this tangent and circle", () => { + let A = new freesewing.Point(5, 5).attr("data-circle", 5); + let B = new freesewing.Point(0, 0); + let C = new freesewing.Point(10, 0); + let intersections = freesewing.utils.lineIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C + ); + expect(intersections.length).to.equal(1); + expect(intersections[0].x).to.equal(5); + expect(intersections[0].y).to.equal(0); + }); -it("Should find one intersection between this line and circle", () => { - let A = new freesewing.Point(5, 5).attr("data-circle", 5); - let B = new freesewing.Point(5, 5); - let C = new freesewing.Point(26, 25); - let intersections = freesewing.utils.lineIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C - ); - expect(intersections.length).to.equal(1); - expect(round(intersections[0].x)).to.equal(8.62); - expect(round(intersections[0].y)).to.equal(8.45); -}); + it("Should find one intersection between this line and circle", () => { + let A = new freesewing.Point(5, 5).attr("data-circle", 5); + let B = new freesewing.Point(5, 5); + let C = new freesewing.Point(26, 25); + let intersections = freesewing.utils.lineIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C + ); + expect(intersections.length).to.equal(1); + expect(round(intersections[0].x)).to.equal(8.62); + expect(round(intersections[0].y)).to.equal(8.45); + }); -it("Should not find an intersections between this line and circle", () => { - let A = new freesewing.Point(5, 5).attr("data-circle", 5); - let B = new freesewing.Point(0, 0); - let C = new freesewing.Point(-10, 0); - let intersections = freesewing.utils.lineIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C - ); - expect(intersections).to.equal(false); -}); + it("Should not find an intersections between this line and circle", () => { + let A = new freesewing.Point(5, 5).attr("data-circle", 5); + let B = new freesewing.Point(0, 0); + let C = new freesewing.Point(-10, 0); + let intersections = freesewing.utils.lineIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C + ); + expect(intersections).to.equal(false); + }); -it("Should find two intersections between this line and circle", () => { - let A = new freesewing.Point(6, 7).attr("data-circle", 5); - let B = new freesewing.Point(0, 10); - let C = new freesewing.Point(10, 0); - let intersections1 = freesewing.utils.lineIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C, - "foo" - ); - let intersections2 = freesewing.utils.lineIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C, - "x" - ); - let intersections3 = freesewing.utils.lineIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C, - "y" - ); - expect(intersections1.length).to.equal(2); - expect(intersections2.length).to.equal(2); - expect(intersections3.length).to.equal(2); - expect(intersections1[0].sitsOn(intersections2[1])).to.equal(true); - expect(intersections1[1].sitsOn(intersections2[0])).to.equal(true); - expect(intersections1[0].sitsOn(intersections3[0])).to.equal(true); - expect(intersections1[1].sitsOn(intersections3[1])).to.equal(true); - expect(round(intersections1[0].x)).to.equal(7.7); - expect(round(intersections1[0].y)).to.equal(2.3); - expect(round(intersections1[1].x)).to.equal(1.3); - expect(round(intersections1[1].y)).to.equal(8.7); -}); + it("Should find two intersections between this line and circle", () => { + let A = new freesewing.Point(6, 7).attr("data-circle", 5); + let B = new freesewing.Point(0, 10); + let C = new freesewing.Point(10, 0); + let intersections1 = freesewing.utils.lineIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C, + "foo" + ); + let intersections2 = freesewing.utils.lineIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C, + "x" + ); + let intersections3 = freesewing.utils.lineIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C, + "y" + ); + expect(intersections1.length).to.equal(2); + expect(intersections2.length).to.equal(2); + expect(intersections3.length).to.equal(2); + expect(intersections1[0].sitsOn(intersections2[1])).to.equal(true); + expect(intersections1[1].sitsOn(intersections2[0])).to.equal(true); + expect(intersections1[0].sitsOn(intersections3[0])).to.equal(true); + expect(intersections1[1].sitsOn(intersections3[1])).to.equal(true); + expect(round(intersections1[0].x)).to.equal(7.7); + expect(round(intersections1[0].y)).to.equal(2.3); + expect(round(intersections1[1].x)).to.equal(1.3); + expect(round(intersections1[1].y)).to.equal(8.7); + }); -it("Should find the intersections of a line and circle", () => { - let A = new freesewing.Point(45, 45).attr("data-circle", 35); - let B = new freesewing.Point(5, 50); - let C = new freesewing.Point(25, 30); - let intersections = freesewing.utils.lineIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C - ); - expect(intersections.length).to.equal(1); - expect(round(intersections[0].x)).to.equal(10); - expect(round(intersections[0].y)).to.equal(45); -}); + it("Should find the intersections of a line and circle", () => { + let A = new freesewing.Point(45, 45).attr("data-circle", 35); + let B = new freesewing.Point(5, 50); + let C = new freesewing.Point(25, 30); + let intersections = freesewing.utils.lineIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C + ); + expect(intersections.length).to.equal(1); + expect(round(intersections[0].x)).to.equal(10); + expect(round(intersections[0].y)).to.equal(45); + }); -it("Should not find intersections of this line and circle", () => { - let A = new freesewing.Point(75, 75).attr("data-circle", 35); - let B = new freesewing.Point(5, 5); - let C = new freesewing.Point(10, 5); - let intersections = freesewing.utils.lineIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C - ); - expect(intersections).to.equal(false); -}); + it("Should not find intersections of this line and circle", () => { + let A = new freesewing.Point(75, 75).attr("data-circle", 35); + let B = new freesewing.Point(5, 5); + let C = new freesewing.Point(10, 5); + let intersections = freesewing.utils.lineIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C + ); + expect(intersections).to.equal(false); + }); -it("Should not find intersections of this line and circle", () => { - let A = new freesewing.Point(45, 45).attr("data-circle", 35); - let B = new freesewing.Point(40, 40); - let C = new freesewing.Point(52, 50); - let intersections = freesewing.utils.lineIntersectsCircle( - A, - A.attributes.get("data-circle"), - B, - C - ); - expect(intersections).to.equal(false); -}); + it("Should not find intersections of this line and circle", () => { + let A = new freesewing.Point(45, 45).attr("data-circle", 35); + let B = new freesewing.Point(40, 40); + let C = new freesewing.Point(52, 50); + let intersections = freesewing.utils.lineIntersectsCircle( + A, + A.attributes.get("data-circle"), + B, + C + ); + expect(intersections).to.equal(false); + }); -it("Should find intersections between circles", () => { - let A = new freesewing.Point(10, 10).attr("data-circle", 15); - let B = new freesewing.Point(30, 30).attr("data-circle", 35); + it("Should find intersections between circles", () => { + let A = new freesewing.Point(10, 10).attr("data-circle", 15); + let B = new freesewing.Point(30, 30).attr("data-circle", 35); - let intersections1 = freesewing.utils.circlesIntersect( - A, - A.attributes.get("data-circle"), - B, - B.attributes.get("data-circle") - ); - let intersections2 = freesewing.utils.circlesIntersect( - A, - A.attributes.get("data-circle"), - B, - B.attributes.get("data-circle"), - "y" - ); - expect(intersections1.length).to.equal(2); - expect(intersections2.length).to.equal(2); - expect(round(intersections1[0].x)).to.equal(-2.81); - expect(round(intersections1[0].y)).to.equal(17.81); - expect(round(intersections1[1].x)).to.equal(17.81); - expect(round(intersections1[1].y)).to.equal(-2.81); - expect(round(intersections2[0].x)).to.equal(17.81); - expect(round(intersections2[0].y)).to.equal(-2.81); - expect(round(intersections2[1].x)).to.equal(-2.81); - expect(round(intersections2[1].y)).to.equal(17.81); -}); + let intersections1 = freesewing.utils.circlesIntersect( + A, + A.attributes.get("data-circle"), + B, + B.attributes.get("data-circle") + ); + let intersections2 = freesewing.utils.circlesIntersect( + A, + A.attributes.get("data-circle"), + B, + B.attributes.get("data-circle"), + "y" + ); + expect(intersections1.length).to.equal(2); + expect(intersections2.length).to.equal(2); + expect(round(intersections1[0].x)).to.equal(-2.81); + expect(round(intersections1[0].y)).to.equal(17.81); + expect(round(intersections1[1].x)).to.equal(17.81); + expect(round(intersections1[1].y)).to.equal(-2.81); + expect(round(intersections2[0].x)).to.equal(17.81); + expect(round(intersections2[0].y)).to.equal(-2.81); + expect(round(intersections2[1].x)).to.equal(-2.81); + expect(round(intersections2[1].y)).to.equal(17.81); + }); -it("Should not find intersections between non-overlapping circles", () => { - let A = new freesewing.Point(10, 10).attr("data-circle", 15); - let B = new freesewing.Point(90, 90).attr("data-circle", 35); + it("Should not find intersections between non-overlapping circles", () => { + let A = new freesewing.Point(10, 10).attr("data-circle", 15); + let B = new freesewing.Point(90, 90).attr("data-circle", 35); - let intersections = freesewing.utils.circlesIntersect( - A, - A.attributes.get("data-circle"), - B, - B.attributes.get("data-circle") - ); - expect(intersections).to.equal(false); -}); + let intersections = freesewing.utils.circlesIntersect( + A, + A.attributes.get("data-circle"), + B, + B.attributes.get("data-circle") + ); + expect(intersections).to.equal(false); + }); -it("Should not find intersections between contained circles", () => { - let A = new freesewing.Point(10, 10).attr("data-circle", 15); - let B = new freesewing.Point(10, 10).attr("data-circle", 35); + it("Should not find intersections between contained circles", () => { + let A = new freesewing.Point(10, 10).attr("data-circle", 15); + let B = new freesewing.Point(10, 10).attr("data-circle", 35); - let intersections = freesewing.utils.circlesIntersect( - A, - A.attributes.get("data-circle"), - B, - B.attributes.get("data-circle") - ); - expect(intersections).to.equal(false); -}); + let intersections = freesewing.utils.circlesIntersect( + A, + A.attributes.get("data-circle"), + B, + B.attributes.get("data-circle") + ); + expect(intersections).to.equal(false); + }); -it("Should not find intersections between identical circles", () => { - let A = new freesewing.Point(10, 10).attr("data-circle", 35); - let B = new freesewing.Point(10, 10).attr("data-circle", 35); + it("Should not find intersections between identical circles", () => { + let A = new freesewing.Point(10, 10).attr("data-circle", 35); + let B = new freesewing.Point(10, 10).attr("data-circle", 35); - let intersections = freesewing.utils.circlesIntersect( - A, - A.attributes.get("data-circle"), - B, - B.attributes.get("data-circle") - ); - expect(intersections).to.equal(false); -}); + let intersections = freesewing.utils.circlesIntersect( + A, + A.attributes.get("data-circle"), + B, + B.attributes.get("data-circle") + ); + expect(intersections).to.equal(false); + }); -it("Should return scale for a given amount of stretch", () => { - expect(freesewing.utils.stretchToScale(0)).to.equal(1); - expect(freesewing.utils.stretchToScale(0.25)).to.equal(0.8); -}); + it("Should return scale for a given amount of stretch", () => { + expect(freesewing.utils.stretchToScale(0)).to.equal(1); + expect(freesewing.utils.stretchToScale(0.25)).to.equal(0.8); + }); -it("Should capitalize a string", () => { - expect(utils.capitalize("test")).to.equal("Test"); - expect(utils.capitalize("Freesewing")).to.equal("Freesewing"); -}); + it("Should capitalize a string", () => { + expect(utils.capitalize("test")).to.equal("Test"); + expect(utils.capitalize("Freesewing")).to.equal("Freesewing"); + }); -it("Should split a curve", () => { - let a = new freesewing.Point(0, 0); - let b = new freesewing.Point(50, 0); - let c = new freesewing.Point(50, 100); - let d = new freesewing.Point(100, 100); - let X = new freesewing.Point(50, 50); - let [c1, c2] = utils.splitCurve(a, b, c, d, X); - expect(round(c1.cp1.x)).to.equal(25); - expect(round(c1.cp1.y)).to.equal(0); - expect(round(c1.cp2.x)).to.equal(37.5); - expect(round(c1.cp2.y)).to.equal(25); - expect(round(c2.cp1.x)).to.equal(62.5); - expect(round(c2.cp1.y)).to.equal(75); - expect(round(c2.cp2.x)).to.equal(75); - expect(round(c2.cp2.y)).to.equal(100); -}); + it("Should split a curve", () => { + let a = new freesewing.Point(0, 0); + let b = new freesewing.Point(50, 0); + let c = new freesewing.Point(50, 100); + let d = new freesewing.Point(100, 100); + let X = new freesewing.Point(50, 50); + let [c1, c2] = utils.splitCurve(a, b, c, d, X); + expect(round(c1.cp1.x)).to.equal(25); + expect(round(c1.cp1.y)).to.equal(0); + expect(round(c1.cp2.x)).to.equal(37.5); + expect(round(c1.cp2.y)).to.equal(25); + expect(round(c2.cp1.x)).to.equal(62.5); + expect(round(c2.cp1.y)).to.equal(75); + expect(round(c2.cp2.x)).to.equal(75); + expect(round(c2.cp2.y)).to.equal(100); + }); -it("Should find where a curve intersects a given X-value", () => { - let a = new freesewing.Point(0, 0); - let b = new freesewing.Point(50, 0); - let c = new freesewing.Point(50, 100); - let d = new freesewing.Point(100, 100); - let i = utils.curveIntersectsX(a, b, c, d, 30); - expect(round(i.x)).to.equal(30); - expect(round(i.y)).to.equal(16); -}); + it("Should find where a curve intersects a given X-value", () => { + let a = new freesewing.Point(0, 0); + let b = new freesewing.Point(50, 0); + let c = new freesewing.Point(50, 100); + let d = new freesewing.Point(100, 100); + let i = utils.curveIntersectsX(a, b, c, d, 30); + expect(round(i.x)).to.equal(30); + expect(round(i.y)).to.equal(16); + }); -it("Should find where a curve intersects a given Y-value", () => { - let a = new freesewing.Point(0, 0); - let b = new freesewing.Point(50, 0); - let c = new freesewing.Point(50, 100); - let d = new freesewing.Point(100, 100); - let i = utils.curveIntersectsY(a, b, c, d, 30); - expect(round(i.x)).to.equal(39.49); - expect(round(i.y)).to.equal(30); -}); + it("Should find where a curve intersects a given Y-value", () => { + let a = new freesewing.Point(0, 0); + let b = new freesewing.Point(50, 0); + let c = new freesewing.Point(50, 100); + let d = new freesewing.Point(100, 100); + let i = utils.curveIntersectsY(a, b, c, d, 30); + expect(round(i.x)).to.equal(39.49); + expect(round(i.y)).to.equal(30); + }); -// Recreate issue #1206 -it("Should find intersecting beams when a line is almost vertical", () => { - let a = new freesewing.Point(225.72, 241); - let b = new freesewing.Point(225.71999999999997, 600); - let i = utils.beamIntersectsY(a, b, 400); - expect(round(i.y)).to.equal(400); -}); + // Recreate issue #1206 + it("Should find intersecting beams when a line is almost vertical", () => { + let a = new freesewing.Point(225.72, 241); + let b = new freesewing.Point(225.71999999999997, 600); + let i = utils.beamIntersectsY(a, b, 400); + expect(round(i.y)).to.equal(400); + }); -it("Should check for valid coordinate", () => { - expect(utils.isCoord(23423.23)).to.equal(true); - expect(utils.isCoord(0)).to.equal(true); - expect(utils.isCoord()).to.equal(false); - expect(utils.isCoord(null)).to.equal(false); - expect(utils.isCoord('hi')).to.equal(false); - expect(utils.isCoord(NaN)).to.equal(false); -}); + it("Should check for valid coordinate", () => { + expect(utils.isCoord(23423.23)).to.equal(true); + expect(utils.isCoord(0)).to.equal(true); + expect(utils.isCoord()).to.equal(false); + expect(utils.isCoord(null)).to.equal(false); + expect(utils.isCoord('hi')).to.equal(false); + expect(utils.isCoord(NaN)).to.equal(false); + }); -it("Should return the correct sample style", () => { - expect(utils.sampleStyle(0, 5)).to.equal("stroke: hsl(-66, 100%, 35%);") - expect(utils.sampleStyle(1, 5)).to.equal("stroke: hsl(0, 100%, 35%);") - expect(utils.sampleStyle(2, 5)).to.equal("stroke: hsl(66, 100%, 35%);") - expect(utils.sampleStyle(3, 5)).to.equal("stroke: hsl(132, 100%, 35%);") - expect(utils.sampleStyle(4, 5)).to.equal("stroke: hsl(198, 100%, 35%);") -}); + it("Should return the correct sample style", () => { + expect(utils.sampleStyle(0, 5)).to.equal("stroke: hsl(-66, 100%, 35%);") + expect(utils.sampleStyle(1, 5)).to.equal("stroke: hsl(0, 100%, 35%);") + expect(utils.sampleStyle(2, 5)).to.equal("stroke: hsl(66, 100%, 35%);") + expect(utils.sampleStyle(3, 5)).to.equal("stroke: hsl(132, 100%, 35%);") + expect(utils.sampleStyle(4, 5)).to.equal("stroke: hsl(198, 100%, 35%);") + }); -it("Should return the correct sample styles", () => { - const styles = [ - "stroke: red;", - "stroke: blue;", - "stroke: green;", - "stroke: pink;", - "stroke: orange;", - ] - for (let i=0;i<5;i++) expect(utils.sampleStyle(i, 5, styles)).to.equal(styles[i]) -}); + it("Should return the correct sample styles", () => { + const styles = [ + "stroke: red;", + "stroke: blue;", + "stroke: green;", + "stroke: pink;", + "stroke: orange;", + ] + for (let i=0;i<5;i++) expect(utils.sampleStyle(i, 5, styles)).to.equal(styles[i]) + }); -it("Should convert degrees to radians", () => { - expect(utils.deg2rad(0)).to.equal(0); - expect(round(utils.deg2rad(69))).to.equal(1.2); -}); + it("Should convert degrees to radians", () => { + expect(utils.deg2rad(0)).to.equal(0); + expect(round(utils.deg2rad(69))).to.equal(1.2); + }); -it("Should convert radians to degrees", () => { - expect(utils.rad2deg(0)).to.equal(0); - expect(round(utils.rad2deg(69))).to.equal(3953.41); -}); + it("Should convert radians to degrees", () => { + expect(utils.rad2deg(0)).to.equal(0); + expect(round(utils.rad2deg(69))).to.equal(3953.41); + }); -it("Should shoulder return two methods for pctBasedOn", () => { - const result = utils.pctBasedOn('chest') - expect(typeof result.toAbs).to.equal("function"); - expect(typeof result.fromAbs).to.equal("function"); - const measurements = { chest: 1000 } - expect(result.toAbs(0.0123, { measurements })).to.equal(12.3) - expect(result.fromAbs(12.3, { measurements })).to.equal(0.0123) -}); + it("Should shoulder return two methods for pctBasedOn", () => { + const result = utils.pctBasedOn('chest') + expect(typeof result.toAbs).to.equal("function"); + expect(typeof result.fromAbs).to.equal("function"); + const measurements = { chest: 1000 } + expect(result.toAbs(0.0123, { measurements })).to.equal(12.3) + expect(result.fromAbs(12.3, { measurements })).to.equal(0.0123) + }); -it("Should generate a part transform", () => { - let pattern = new freesewing.Pattern(); - pattern.settings.mode = "draft"; - let part = new pattern.Part(); - let short = part.shorthand(); - part.points.from = new short.Point(2, 2); - part.points.to = new short.Point(19, 76); - part.paths.test = new short.Path() - .move(part.points.from) - .line(part.points.to); - part.stack(); - const transform = utils.generatePartTransform(30,60,90,true,true,part) - expect(transform.transform).to.equal(`translate(${30 + part.topLeft.x + part.bottomRight.x} ${60 + part.topLeft.y + part.bottomRight.y}) scale(-1 -1) rotate(90 ${part.topLeft.x + part.width/2} ${part.topLeft.y + part.height/2})`); + it("Should generate a part transform", () => { + let pattern = new freesewing.Pattern(); + pattern.settings.mode = "draft"; + let part = new pattern.Part(); + let short = part.shorthand(); + part.points.from = new short.Point(2, 2); + part.points.to = new short.Point(19, 76); + part.paths.test = new short.Path() + .move(part.points.from) + .line(part.points.to); + part.stack(); + const transform = utils.generatePartTransform(30,60,90,true,true,part) + expect(transform.transform).to.equal(`translate(${30 + part.topLeft.x + part.bottomRight.x} ${60 + part.topLeft.y + part.bottomRight.y}) scale(-1 -1) rotate(90 ${part.topLeft.x + part.width/2} ${part.topLeft.y + part.height/2})`); + }); });