diff --git a/README.md b/README.md index 25f8e10..23c0f78 100644 --- a/README.md +++ b/README.md @@ -90,3 +90,5 @@ sh build.sh 22. 2016-1-5 增加复合字形编辑和复制功能. 23. 2016-2-25 增加字形导出svg和png功能. + +24. 2016-3-7 将path的布尔操作库替换成paper.js的路径库. diff --git a/demo/editor.html b/demo/editor.html index 2f2d0a1..00830cf 100644 --- a/demo/editor.html +++ b/demo/editor.html @@ -5,7 +5,7 @@ 测试editor - + @@ -25,7 +25,8 @@ } }); define('jquery', $); - define('ClipperLib', window.ClipperLib); + paper.install(window); + define('paper', paper);
diff --git a/demo/editortest.html b/demo/editortest.html index 6fdd707..c480dc4 100644 --- a/demo/editortest.html +++ b/demo/editortest.html @@ -5,7 +5,7 @@ 测试editor - + @@ -25,7 +25,8 @@ } }); define('jquery', $); - define('ClipperLib', window.ClipperLib); + paper.install(window); + define('paper', paper); diff --git a/demo/js/paper-boolean.js b/demo/js/paper-boolean.js index 08028c0..37caaaf 100644 --- a/demo/js/paper-boolean.js +++ b/demo/js/paper-boolean.js @@ -8,7 +8,6 @@ define(function (require) { var contour2svg = require('fonteditor-core/ttf/util/contour2svg'); var contours2svg = require('fonteditor-core/ttf/util/contours2svg'); - var booleanStyle = { fillColor: new Color(1, 0, 0, 0.5), strokeColor: new Color(0, 0, 0), @@ -27,73 +26,44 @@ define(function (require) { strokeWidth: 1 }; - var contour1 = [{"x":394,"y":138},{"x":339,"y":5},{"x":164,"y":263},{"x":79,"y":165,"onCurve":true},{"x":286,"y":4,"onCurve":true},{"x":385,"y":-80},{"x":422,"y":83},{"x":422,"y":158},{"x":369,"y":211},{"x":295,"y":211}]; - - var contour2 = [{"x":597,"y":61,"onCurve":true},{"x":597,"y":62},{"x":595,"y":63},{"x":594,"y":64,"onCurve":true},{"x":586,"y":78},{"x":572,"y":84,"onCurve":true},{"x":459,"y":177},{"x":312,"y":177,"onCurve":true},{"x":163,"y":177},{"x":49,"y":81,"onCurve":true},{"x":42,"y":76},{"x":37,"y":70,"onCurve":true},{"x":36,"y":69},{"x":33,"y":66},{"x":33,"y":65,"onCurve":true},{"x":26,"y":53},{"x":26,"y":39,"onCurve":true},{"x":26,"y":19},{"x":55,"y":-10},{"x":75,"y":-10,"onCurve":true},{"x":91,"y":-10},{"x":105,"y":0,"onCurve":true},{"x":193,"y":80},{"x":312,"y":80,"onCurve":true},{"x":435,"y":80},{"x":524,"y":-4,"onCurve":true},{"x":526,"y":-2,"onCurve":true},{"x":538,"y":-10},{"x":552,"y":-10,"onCurve":true},{"x":573,"y":-10},{"x":601,"y":19},{"x":601,"y":39,"onCurve":true},{"x":601,"y":50},{"x":596,"y":60,"onCurve":true}]; - - - var contours1 = [[{"x":188.24373119358074,"y":338,"onCurve":true},{"x":207.57372116349052,"y":338},{"x":218.70310932798395,"y":307.73305954825463,"onCurve":true},{"x":221.04613841524576,"y":301.1981519507187},{"x":222.21765295887667,"y":285.7207392197125,"onCurve":true},{"x":222.21765295887667,"y":253.73408624229978},{"x":200.54463390170508,"y":237.22484599589325,"onCurve":true},{"x":193.80842527582752,"y":233.44147843942505},{"x":187.65797392176523,"y":233.44147843942505,"onCurve":true},{"x":161.88465396188565,"y":233.44147843942505},{"x":153.68405215646942,"y":275.7464065708419,"onCurve":true},{"x":153.09829488465402,"y":282.28131416837783},{"x":153.09829488465402,"y":285.7207392197125,"onCurve":true},{"x":153.09829488465402,"y":320.45893223819303},{"x":177.1143430290873,"y":335.9363449691992,"onCurve":true},{"x":182.67903711133397,"y":338}],[{"x":280.20762286860577,"y":330.0893223819302,"onCurve":true},{"x":293.3871614844534,"y":330.0893223819302},{"x":307.445336008024,"y":309.79671457905545,"onCurve":true},{"x":315.3530591775326,"y":296.0390143737166},{"x":315.3530591775326,"y":282.96919917864477,"onCurve":true},{"x":315.3530591775326,"y":261.30082135523617},{"x":296.3159478435306,"y":239.288501026694,"onCurve":true},{"x":285.77231695085254,"y":229.31416837782342},{"x":274.0571715145436,"y":229.31416837782342,"onCurve":true},{"x":272.8856569709128,"y":229.31416837782342,"onCurve":true},{"x":250.6268806419257,"y":229.31416837782342},{"x":242.13340020060184,"y":254.76591375770022,"onCurve":true},{"x":240.08324974924778,"y":264.0523613963039},{"x":240.08324974924778,"y":272.65092402464063,"onCurve":true},{"x":240.08324974924778,"y":306.7012320328542},{"x":270.542627883651,"y":327.6817248459959,"onCurve":true},{"x":274.0571715145436,"y":328.7135523613963}],[{"x":114.14543630892683,"y":260.95687885010267,"onCurve":true},{"x":137.5757271815446,"y":260.95687885010267},{"x":151.92678034102312,"y":226.21868583162217,"onCurve":true},{"x":153.09829488465402,"y":216.93223819301846},{"x":153.68405215646942,"y":207.30184804928132,"onCurve":true},{"x":153.68405215646942,"y":172.56365503080082},{"x":129.66800401203614,"y":161.90143737166323,"onCurve":true},{"x":123.51755265797397,"y":158.80595482546198},{"x":114.14543630892683,"y":158.80595482546198,"onCurve":true},{"x":86.90772316950847,"y":158.80595482546198},{"x":79,"y":201.79876796714575,"onCurve":true},{"x":79,"y":206.61396303901438,"onCurve":true},{"x":79,"y":226.21868583162217},{"x":90.71514543630894,"y":245.82340862422996,"onCurve":true},{"x":100.67301905717147,"y":260.95687885010267}],[{"x":331.4613841524574,"y":235.16119096509237,"onCurve":true},{"x":332.6328986960882,"y":235.16119096509237,"onCurve":true},{"x":358.69909729187566,"y":235.16119096509237},{"x":368.0712136409228,"y":205.2381930184805,"onCurve":true},{"x":371,"y":199.3911704312115},{"x":371,"y":190.79260780287473,"onCurve":true},{"x":371,"y":183.5698151950719,"onCurve":true},{"x":371,"y":136.44969199178644},{"x":334.09729187562687,"y":136.44969199178644,"onCurve":true},{"x":308.61685055165503,"y":136.44969199178644},{"x":300.12337011033105,"y":158.80595482546198,"onCurve":true},{"x":297.4874623871615,"y":171.18788501026694},{"x":297.4874623871615,"y":184.25770020533878,"onCurve":true},{"x":297.4874623871615,"y":235.16119096509237}]]; - - var contours2 = [[{"x":316.0105315947844,"y":137.23123670845985,"onCurve":true},{"x":316.0105315947844,"y":100.45054415861722},{"x":261.26634554827274,"y":48.744353182751524},{"x":183.7547176412961,"y":48.744353182751524},{"x":129.01053159478442,"y":100.45054415861722},{"x":129.01053159478442,"y":137.23123670845985,"onCurve":true},{"x":129.01053159478442,"y":162.01822516596246},{"x":143.59192694362162,"y":184.67299956260462,"onCurve":true},{"x":144.87099671106353,"y":186.27216010824998},{"x":165.3361129901332,"y":214.25746965704326},{"x":181.70820601338914,"y":238.24487784172322},{"x":201.9175083389705,"y":275.5586239067809},{"x":207.0337874087379,"y":291.8167561208418,"onCurve":true},{"x":208.56867112966813,"y":296.8807645153853},{"x":217.7779734552496,"y":302.7443531827515},{"x":227.24308973431926,"y":302.7443531827515},{"x":236.70820601338914,"y":296.8807645153853},{"x":237.98727578083094,"y":291.8167561208418,"onCurve":true},{"x":243.10355485059836,"y":275.5586239067809},{"x":263.3128571761798,"y":238.24487784172322},{"x":279.68495019943566,"y":214.25746965704326},{"x":300.1500664785053,"y":186.27216010824998},{"x":301.42913624594723,"y":184.67299956260462,"onCurve":true},{"x":316.0105315947844,"y":162.55127868117756}]]; + var path1 = 'M316.01053,137.23124c0,-24.52046 -9.12403,-45.39839 -27.37209,-62.63379c-18.24806,-17.2354 -40.2907,-25.8531 -66.12791,-25.8531c-25.83721,0 -47.87984,8.6177 -66.12791,25.8531c-18.24806,17.2354 -27.37209,38.11333 -27.37209,62.63379c0,16.52466 4.86047,32.33858 14.5814,47.44176c0.85271,1.06611 4.68992,6.26338 11.51163,15.59182c6.82171,9.32844 12.96124,17.99056 18.4186,25.98636c5.45736,7.9958 11.55426,18.21266 18.2907,30.65058c6.73643,12.43792 11.81008,24.07625 15.22093,34.91501c1.02326,3.37601 3.06977,6.04127 6.13953,7.9958c3.06977,1.95453 6.18217,2.93179 9.33721,2.93179c3.15504,0 6.31008,-0.97726 9.46512,-2.93179c3.15504,-1.95453 5.15891,-4.6198 6.01163,-7.9958c3.41085,-10.83875 8.4845,-22.47709 15.22093,-34.91501c6.73643,-12.43792 12.83333,-22.65477 18.2907,-30.65058c5.45736,-7.9958 11.5969,-16.65792 18.4186,-25.98636c6.82171,-9.32844 10.65891,-14.52571 11.51163,-15.59182c9.72093,-14.74781 14.5814,-30.56173 14.5814,-47.44176zM261.96983,180.20868c-0.42636,0.53305 -2.34496,3.13169 -5.75581,7.79591c-3.41085,4.66422 -6.48062,8.99528 -9.2093,12.99318c-2.72868,3.9979 -5.77713,9.10633 -9.14535,15.32529c-3.36822,6.21896 -5.90504,12.03813 -7.61047,17.4575c-0.42636,1.688 -1.42829,3.02064 -3.00581,3.9979c-1.57752,0.97726 -3.15504,1.4659 -4.73256,1.4659c-1.57752,0 -3.13372,-0.48863 -4.6686,-1.4659c-1.53488,-0.97726 -2.55814,-2.3099 -3.06977,-3.9979c-1.70543,-5.41938 -4.24225,-11.23854 -7.61047,-17.4575c-3.36822,-6.21896 -6.41667,-11.32739 -9.14535,-15.32529c-2.72868,-3.9979 -5.79845,-8.32896 -9.2093,-12.99318c-3.41085,-4.66422 -5.32946,-7.26285 -5.75581,-7.79591c-4.86047,-7.55159 -7.2907,-15.45855 -7.2907,-23.72088c0,-12.26023 4.56202,-22.6992 13.68605,-31.31689c9.12403,-8.6177 20.14535,-12.92655 33.06395,-12.92655c12.9186,0 23.93992,4.30885 33.06395,12.92655c9.12403,8.6177 13.68605,19.05666 13.68605,31.31689c0,8.44001 -2.43023,16.34697 -7.2907,23.72088z'; var spliter = [ {"x":307,"y":430,"onCurve":true},{"x":119,"y":-14,"onCurve":true} ]; - // 单个路径boolean操作 - function contourboolean(contour1, contour2, operation) { - var path1 = new paper.Path(contour2svg(contour1)); - var path2 = new paper.Path(contour2svg(contour2)); - - // var booleanPath = path1.unite(path2); // 合并 - // var booleanPath = path1.intersect(path2); // 相交 - // var booleanPath = path1.subtract(path2); // 减去 - // var booleanPath = path1.exclude(path2); // 差集 - var booleanPath = path1.divide(path2); // 分割 - - booleanPath.style = pathStyleBoolean; - console.log(booleanPath); - view.draw(); - } - - // 复合路径boolean操作 - function contoursboolean(contours1, contours2, operation) { - var path1 = new paper.CompoundPath(contours2svg(contours1)); - var path2 = new paper.CompoundPath(contours2svg(contours2)); - - //var booleanPath = path1.unite(path2); // 合并 - var booleanPath = path1.intersect(path2); // 相交 - // var booleanPath = path1.subtract(path2); // 减去 - // var booleanPath = path1.exclude(path2); // 差集 - //var booleanPath = path1.divide(path2); // 分割 - - booleanPath.style = pathStyleBoolean; - view.draw(); - var pathData = booleanPath.getPathData(); - $('#pathresult').attr('d', pathData); - } // 复合路径分割操作 function contoursdivide(contours1, spliter, operation) { - var path1 = new paper.CompoundPath(contours2svg(contours1)); + var path1 = new paper.CompoundPath(contours1); var path2 = new paper.Path({ segments: [ [spliter[0].x, spliter[0].y], - [spliter[1].x, spliter[1].y], [spliter[1].x, spliter[1].y] ], - closed: true + closed: false }); - var booleanPath = path1.divide(path2); // 分割 - - booleanPath.style = pathStyleBoolean; - view.draw(); + var intersections = path1.getIntersections(path2); // 分割 + intersections.forEach(function (ins) { + console.log(ins.getPoint()); + var result = ins.split(); + //console.log(result); + }); var a = 0; - var pathData = booleanPath.getChildren().map(function (path) { + path1.children.forEach(function (path) { + path.segments[0].clearHandles(); + path.segments[path.segments.length - 1].clearHandles(); + path.closePath(); if (++a % 2) { - path.moveTo(a * 10, 0); + path.position.x -= 20; } + }); + path1.resolveCrossings().reorient(); + + path1.style = pathStyleBoolean; + view.draw(); + var pathData = path1.getChildren().map(function (path) { return path.getPathData(); }).join(''); $('#pathresult').attr('d', pathData); @@ -108,15 +78,10 @@ define(function (require) { init: function () { paper.setup(document.getElementById('canvas')); - - // $('#path1').attr('d', contour2svg(contour1)); - // $('#path2').attr('d', contour2svg(contour2)); - // contourboolean(contour1, contour2); - - $('#path1').attr('d', contours2svg(contours2)); + $('#path1').attr('d', path1); $('#path2').attr('d', contour2svg(spliter)); // contoursboolean(contours1, contours2); - contoursdivide(contours2, spliter); + contoursdivide(path1, spliter); } }; diff --git a/src/graphics/pathBoolean.js b/src/graphics/pathBoolean.js index 5974f09..cd6eb57 100644 --- a/src/graphics/pathBoolean.js +++ b/src/graphics/pathBoolean.js @@ -6,6 +6,7 @@ define(function (require) { var contours2svg = require('fonteditor-core/ttf/util/contours2svg'); var path2contours = require('fonteditor-core/ttf/svg/path2contours'); + var reducePath = require('./reducePath'); var paper = require('paper'); var RELATION = { @@ -65,6 +66,12 @@ define(function (require) { var contours = resultPath ? getContours(resultPath) : paths; paper.clear(); + + // 清除重复的冗余节点 + for (var i = 0, l = contours.length; i < l; i++) { + contours[i] = reducePath(contours[i]); + } + return contours; } diff --git a/src/graphics/pathSplitBySegment.js b/src/graphics/pathSplitBySegment.js index 4821ca2..3e72e23 100644 --- a/src/graphics/pathSplitBySegment.js +++ b/src/graphics/pathSplitBySegment.js @@ -5,6 +5,31 @@ define( function (require) { + var path2contours = require('fonteditor-core/ttf/svg/path2contours'); + var contours2svg = require('fonteditor-core/ttf/util/contours2svg'); + + var reducePath = require('./reducePath'); + var paper = require('paper'); + + + + function initPaper() { + if (!paper.project) { + paper.setup(document.createElement('canvas')); + } + } + + function getPath(contours) { + // 根据contours获取paper.Path对象 + var d = contours2svg(contours); + return new paper.CompoundPath(d); + } + + function getContours(path) { + // 根据path获取contours数组 + var d = path.getPathData(); + return path2contours(d); + } /** * 线段切割路径 @@ -15,7 +40,35 @@ define( * @return {Array|false} 切割后路径或者false */ function pathSplitBySegment(paths, p0, p1) { - return paths; + initPaper(); + var subject = getPath(paths); + var clipper = new paper.Path({ + segments: [ + [p0.x, p0.y], + [p1.x, p1.y] + ], + closed: false + }); + + var intersections = subject.getIntersections(clipper); // 分割 + if (!intersections || !intersections.length) { + return paths; + } + // 根据交点分割路径 + intersections.forEach(function (spliter) { + var result = spliter.split(); + }); + // 闭合路径 + subject.children.forEach(function (path) { + path.segments[0].clearHandles(); + path.segments[path.segments.length - 1].clearHandles(); + path.closePath(); + }); + subject.resolveCrossings().reorient(); + var contours = getContours(subject) ; + paper.clear(); + + return contours; } return pathSplitBySegment;