replace clipper to paper as path boolean lib
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
<title>测试editor combine</title>
|
||||
<script src="../dep/esl.js"></script>
|
||||
<script src="../dep/jquery.min.js"></script>
|
||||
<script src="../dep/clipper.js"></script>
|
||||
<script src="../dep/paper-full.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./css/editor.css">
|
||||
<style id="font-face"></style>
|
||||
</head>
|
||||
@@ -24,7 +24,8 @@
|
||||
}
|
||||
});
|
||||
define('jquery', $);
|
||||
define('ClipperLib', window.ClipperLib);
|
||||
paper.install(window);
|
||||
define('paper', paper);
|
||||
</script>
|
||||
|
||||
<div id="render-view" class="render-view glyf-editor" oncontextMenu="return false"></div>
|
||||
|
||||
@@ -13,7 +13,6 @@ define(
|
||||
var editor = require('editor/main');
|
||||
var shape_baidu = require('demo/../data/contours-2');
|
||||
var isPathCross = require('graphics/isPathCross');
|
||||
var pathJoin = require('graphics/pathJoin');
|
||||
var util = require('graphics/util');
|
||||
|
||||
var currentEditor;
|
||||
|
||||
126
demo/js/paper-boolean.js
Normal file
126
demo/js/paper-boolean.js
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @file paperjs path boolean 操作
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
define(function (require) {
|
||||
var paper = require('paper');
|
||||
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),
|
||||
strokeWidth: 1.5
|
||||
};
|
||||
|
||||
var pathStyleNormal = {
|
||||
strokeColor: new Color(0, 0, 0),
|
||||
fillColor: new Color(0, 0, 0, 0.1),
|
||||
strokeWidth: 1
|
||||
};
|
||||
|
||||
var pathStyleBoolean = {
|
||||
strokeColor: new Color(0.8),
|
||||
fillColor: new Color(0, 0, 0, 0.5),
|
||||
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 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 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
|
||||
});
|
||||
|
||||
var booleanPath = path1.divide(path2); // 分割
|
||||
|
||||
booleanPath.style = pathStyleBoolean;
|
||||
view.draw();
|
||||
var a = 0;
|
||||
var pathData = booleanPath.getChildren().map(function (path) {
|
||||
if (++a % 2) {
|
||||
path.moveTo(a * 10, 0);
|
||||
}
|
||||
return path.getPathData();
|
||||
}).join('');
|
||||
$('#pathresult').attr('d', pathData);
|
||||
}
|
||||
|
||||
|
||||
var entry = {
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
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));
|
||||
$('#path2').attr('d', contour2svg(spliter));
|
||||
// contoursboolean(contours1, contours2);
|
||||
contoursdivide(contours2, spliter);
|
||||
}
|
||||
};
|
||||
|
||||
entry.init();
|
||||
|
||||
return entry;
|
||||
});
|
||||
48
demo/paper-boolean.html
Normal file
48
demo/paper-boolean.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>paperjs path boolean操作</title>
|
||||
<script src="../dep/esl.js"></script>
|
||||
<script src="../dep/jquery.min.js"></script>
|
||||
<script src="../dep/paper-full.js"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
path {
|
||||
stroke-width: 2;
|
||||
stroke: red;
|
||||
fill: #666;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<svg width="800" height="800" viewBox="-50 -50 800 800">
|
||||
<path id="path1"></path>
|
||||
<path id="path2"></path>
|
||||
</svg>
|
||||
<svg width="800" height="800" viewBox="-50 -50 800 800">
|
||||
<path id="pathresult"></path>
|
||||
</svg>
|
||||
<canvas id="canvas" width="800" height="800"></canvas>
|
||||
<script>
|
||||
require.config({
|
||||
baseUrl: '../src',
|
||||
paths: {
|
||||
demo: '../demo/js',
|
||||
'fonteditor-core': '../dep/fonteditor-core/src'
|
||||
}
|
||||
});
|
||||
define('jquery', $);
|
||||
|
||||
paper.install(window);
|
||||
define('paper', paper);
|
||||
</script>
|
||||
|
||||
<script>require(['demo/paper-boolean'])</script>
|
||||
</body>
|
||||
</html>
|
||||
6985
dep/clipper.js
6985
dep/clipper.js
File diff suppressed because it is too large
Load Diff
13704
dep/paper-full.js
Executable file
13704
dep/paper-full.js
Executable file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -147,7 +147,7 @@
|
||||
<script src="./dep/jquery.min.js"></script>
|
||||
<script src="./dep/jqColorPicker.min.js"></script>
|
||||
<script src="./dep/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="./dep/clipper.js"></script>
|
||||
<script src="./dep/paper-full.js"></script>
|
||||
<script src="./dep/hidpi-canvas.js"></script>
|
||||
<script>
|
||||
window.language = '${lang.lang}';
|
||||
@@ -167,7 +167,8 @@
|
||||
}
|
||||
});
|
||||
define('jquery', window.jQuery);
|
||||
define('ClipperLib', window.ClipperLib);
|
||||
paper.install(window);
|
||||
define('paper', window.paper);
|
||||
require(['fonteditor/main'])
|
||||
</script>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var pathJoin = require('graphics/pathJoin');
|
||||
var pathBoolean = require('graphics/pathBoolean');
|
||||
var lang = require('common/lang');
|
||||
var pathSplitBySegment = require('graphics/pathSplitBySegment');
|
||||
var computeBoundingBox = require('graphics/computeBoundingBox');
|
||||
@@ -18,7 +18,7 @@ define(
|
||||
return path.points;
|
||||
});
|
||||
|
||||
var result = pathJoin(pathList, relation);
|
||||
var result = pathBoolean(pathList, relation);
|
||||
var i;
|
||||
var l;
|
||||
|
||||
@@ -82,7 +82,7 @@ define(
|
||||
* @param {Array} shapes 路径对象数组
|
||||
*/
|
||||
joinshapes: function (shapes) {
|
||||
combineShape.call(this, shapes, pathJoin.Relation.join);
|
||||
combineShape.call(this, shapes, pathBoolean.Relation.join);
|
||||
this.refreshSelected(shapes);
|
||||
},
|
||||
|
||||
@@ -92,7 +92,7 @@ define(
|
||||
* @param {Array} shapes 路径对象数组
|
||||
*/
|
||||
intersectshapes: function (shapes) {
|
||||
combineShape.call(this, shapes, pathJoin.Relation.intersect);
|
||||
combineShape.call(this, shapes, pathBoolean.Relation.intersect);
|
||||
this.refreshSelected(shapes);
|
||||
},
|
||||
|
||||
@@ -102,7 +102,7 @@ define(
|
||||
* @param {Array} shapes 路径对象数组
|
||||
*/
|
||||
tangencyshapes: function (shapes) {
|
||||
combineShape.call(this, shapes, pathJoin.Relation.tangency);
|
||||
combineShape.call(this, shapes, pathBoolean.Relation.tangency);
|
||||
this.refreshSelected(shapes);
|
||||
},
|
||||
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
/**
|
||||
* @file 路径裁剪
|
||||
* @author kekee000@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var ClipperLib = require('ClipperLib');
|
||||
|
||||
/* eslint-disable new-cap */
|
||||
|
||||
/**
|
||||
* 将数据转换成clipper格式
|
||||
*
|
||||
* @param {Array} contour 轮廓集合
|
||||
* @return {contour}
|
||||
*/
|
||||
function transformData(contour) {
|
||||
for (var i = 0, l = contour.length; i < l; i++) {
|
||||
contour[i].X = contour[i].x;
|
||||
contour[i].Y = contour[i].y;
|
||||
}
|
||||
return contour;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据转换回小写格式
|
||||
*
|
||||
* @param {Array} contours 轮廓集合
|
||||
* @return {contour}
|
||||
*/
|
||||
function transbackData(contours) {
|
||||
var result = [];
|
||||
contours.forEach(function (contour) {
|
||||
var path = [];
|
||||
for (var i = 0, l = contour.length; i < l; i++) {
|
||||
path.push({
|
||||
x: contour[i].X,
|
||||
y: contour[i].Y,
|
||||
onCurve: true
|
||||
});
|
||||
}
|
||||
result.push(path);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加路径
|
||||
*
|
||||
* @param {Array} contour 轮廓集合
|
||||
* @param {number} polyType 填充规则
|
||||
* @param {boolean} isClosed 是否闭合
|
||||
*/
|
||||
function addPath(contour, polyType, isClosed) {
|
||||
contour = transformData(contour);
|
||||
ClipperLib.JS.ScaleUpPath(contour, this.scale);
|
||||
this.clipper.AddPath(contour, polyType, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 裁剪组件
|
||||
*
|
||||
* @param {Object} options 选项参数
|
||||
*/
|
||||
function Clipper(options) {
|
||||
options = options || {};
|
||||
this.clipType = options.clipType || ClipperLib.ClipType.ctXor;
|
||||
this.fillType = options.fillType || ClipperLib.PolyFillType.pftNonZero;
|
||||
this.scale = options.scale || 100000;
|
||||
this.clipper = new ClipperLib.Clipper();
|
||||
}
|
||||
|
||||
Clipper.prototype.addSubject = function (contour, isClosed) {
|
||||
addPath.call(this, contour, ClipperLib.PolyType.ptSubject, isClosed);
|
||||
};
|
||||
|
||||
Clipper.prototype.addClip = function (contour, isClosed) {
|
||||
addPath.call(this, contour, ClipperLib.PolyType.ptClip, isClosed);
|
||||
};
|
||||
|
||||
/**
|
||||
* 执行裁剪路径
|
||||
*
|
||||
* @param {number} relation 裁剪方法, 相交、相切、合并
|
||||
* @return {Array} 裁剪后的路径
|
||||
*/
|
||||
Clipper.prototype.execute = function (relation) {
|
||||
var result = [];
|
||||
var succeeded = this.clipper.Execute(relation, result, this.fillType, this.fillType);
|
||||
if (succeeded) {
|
||||
result = ClipperLib.Clipper.SimplifyPolygons(result, this.fillType);
|
||||
ClipperLib.JS.ScaleDownPaths(result, this.scale);
|
||||
return transbackData(result);
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
return Clipper;
|
||||
}
|
||||
);
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* @file bezier曲线拟合成线段
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var util = require('graphics/util');
|
||||
var ceilPoint = util.ceilPoint;
|
||||
var getPointHash = util.getPointHash;
|
||||
var getBezierQ2Point = require('math/getBezierQ2Point');
|
||||
|
||||
/**
|
||||
* 将bezier曲线转换成clipper可处理的直线
|
||||
*
|
||||
* @param {Array} contour 轮廓
|
||||
* @param {Array} bezierHash 记录bezier的哈希,以便于转换回去
|
||||
* @return {Array}
|
||||
*/
|
||||
function bezier2Segment(contour, bezierHash) {
|
||||
var curPoint;
|
||||
var prevPoint;
|
||||
var nextPoint;
|
||||
var result = [];
|
||||
|
||||
for (var i = 0, l = contour.length; i < l; i++) {
|
||||
if (!contour[i].onCurve) {
|
||||
curPoint = contour[i];
|
||||
prevPoint = i === 0 ? contour[l - 1] : contour[i - 1];
|
||||
nextPoint = i === l - 1 ? contour[0] : contour[i + 1];
|
||||
var firstPoint = ceilPoint(getBezierQ2Point(prevPoint, curPoint, nextPoint, 0.1));
|
||||
var lastPoint = ceilPoint(getBezierQ2Point(prevPoint, curPoint, nextPoint, 0.9));
|
||||
bezierHash[getPointHash(firstPoint)] = curPoint;
|
||||
bezierHash[getPointHash(lastPoint)] = curPoint;
|
||||
|
||||
result.push(firstPoint);
|
||||
for (var j = 2; j < 9; j++) {
|
||||
result.push(ceilPoint(getBezierQ2Point(prevPoint, curPoint, nextPoint, j * 0.1)));
|
||||
}
|
||||
result.push(lastPoint);
|
||||
}
|
||||
else {
|
||||
result.push(contour[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
return bezier2Segment;
|
||||
}
|
||||
);
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* @file 获取线段和路径的交点
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var getJoint = require('./getJoint');
|
||||
|
||||
/**
|
||||
* 求路径和曲线段的交点集合
|
||||
* @param {Array} path 路径
|
||||
* @param {Object} p0 p0
|
||||
* @param {Object} p1 p`
|
||||
* @param {Object} i 线段的索引
|
||||
*
|
||||
* @return {Array} 交点数组
|
||||
*/
|
||||
return function (path, p0, p1, i) {
|
||||
return getJoint(path, 'L', p0, p1, 0, i || 0);
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* @file 根据路径交点对路径进行插值,
|
||||
* 对bezier曲线上的交点分割bezier曲线,对直线分割成直线
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var bezierQ2Split = require('math/bezierQ2Split');
|
||||
var getBezierQ2T = require('math/getBezierQ2T');
|
||||
var util = require('graphics/util');
|
||||
var ceilPoint = util.ceilPoint;
|
||||
|
||||
/**
|
||||
* 点分割贝塞尔曲线
|
||||
* @param {Object} p0 p0
|
||||
* @param {Object} p1 p1
|
||||
* @param {Object} p2 p2
|
||||
* @param {Array} points 点数组
|
||||
* @return {Array} 分割后的结果
|
||||
*/
|
||||
function bezierSplitByPoints(p0, p1, p2, points) {
|
||||
var p;
|
||||
var result = [p0];
|
||||
var bezierArray;
|
||||
var pp0 = p0;
|
||||
var pp1 = p1;
|
||||
|
||||
// 对交点按照t值从小到大排序的点
|
||||
points = points.map(function (p) {
|
||||
p.t = getBezierQ2T(p0, p1, p2, p);
|
||||
return p;
|
||||
}).sort(function (a, b) {
|
||||
return a.t - b.t;
|
||||
});
|
||||
|
||||
while (p = points.shift()) {
|
||||
bezierArray = bezierQ2Split(pp0, pp1, p2, p);
|
||||
if (bezierArray[1]) {
|
||||
bezierArray[0][2].onCurve = true;
|
||||
result.push(bezierArray[0][1]);
|
||||
result.push(bezierArray[0][2]);
|
||||
pp0 = bezierArray[1][0];
|
||||
pp1 = bezierArray[1][1];
|
||||
}
|
||||
}
|
||||
result.push(pp1);
|
||||
result.push(p2);
|
||||
return result.map(function (p) {
|
||||
return ceilPoint(p);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 对路径进按分割点进行插值
|
||||
* @param {Array} path 路径点集
|
||||
* @param {Array} joints 交点集
|
||||
* @example
|
||||
*
|
||||
* joint = [
|
||||
* {
|
||||
* "index": 1,
|
||||
* "points": {
|
||||
* "x": 1,
|
||||
* "y": 1
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* @return {Array} 插值后的路径
|
||||
*/
|
||||
function interpolatePathByJoint(path, joints) {
|
||||
var splice = Array.prototype.splice;
|
||||
joints.sort(function (a, b) {
|
||||
return b.index - a.index;
|
||||
}).forEach(function (joint) {
|
||||
var i = joint.index;
|
||||
var cur = path[i];
|
||||
// 分割bezier曲线
|
||||
if (!cur.onCurve) {
|
||||
var prev = i === 0 ? path[path.length - 1] : path[i - 1];
|
||||
var next = i === path.length - 1 ? path[0] : path[i + 1];
|
||||
var result = bezierSplitByPoints(prev, cur, next, joint.points);
|
||||
splice.apply(path, [i, 1].concat(result.slice(1, result.length - 1)));
|
||||
}
|
||||
// 分割直线
|
||||
else {
|
||||
splice.apply(path, [i, 0].concat(joint.points.map(function (p) {
|
||||
p.onCurve = true;
|
||||
return p;
|
||||
})));
|
||||
}
|
||||
});
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
return interpolatePathByJoint;
|
||||
}
|
||||
);
|
||||
@@ -1,155 +0,0 @@
|
||||
/**
|
||||
* @file 路径交点插值,对bezier曲线上的交点分割bezier曲线
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var isBezierSegmentCross = require('graphics/isBezierSegmentCross');
|
||||
var isBezierCross = require('graphics/isBezierCross');
|
||||
var interpolatePathByJoint = require('graphics/join/interpolatePathByJoint');
|
||||
var util = require('graphics/util');
|
||||
var isPointOverlap = util.isPointOverlap;
|
||||
|
||||
/**
|
||||
* 线段分割贝塞尔曲线
|
||||
* @param {Object} p0 p0
|
||||
* @param {Object} p1 p1
|
||||
* @param {Object} p2 p2
|
||||
* @param {Object} s0 s0
|
||||
* @param {Object} s1 s1
|
||||
* @return {Array} 分割后的结果
|
||||
*/
|
||||
function getBezierSegmentJoint(p0, p1, p2, s0, s1) {
|
||||
var result;
|
||||
if (result = isBezierSegmentCross(p0, p1, p2, s0, s1)) {
|
||||
return result.filter(function (p) {
|
||||
return !isPointOverlap(p, p0) && !isPointOverlap(p, p2);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 贝塞尔曲线分割
|
||||
*
|
||||
* @param {Object} p0 p0
|
||||
* @param {Object} p1 p1
|
||||
* @param {Object} p2 p2
|
||||
* @param {Object} t0 t0
|
||||
* @param {Object} t1 t1
|
||||
* @param {Object} t2 t2
|
||||
* @return {Array} 分割后的结果
|
||||
*/
|
||||
function getbezierCrossJoint(p0, p1, p2, t0, t1, t2) {
|
||||
var result;
|
||||
if (result = isBezierCross(
|
||||
p0, p1, p2,
|
||||
t0, t1, t2)) {
|
||||
|
||||
var pResult = result.slice(0).filter(function (p) {
|
||||
return !isPointOverlap(p, p0) && !isPointOverlap(p, p2);
|
||||
});
|
||||
|
||||
var tResult = result.filter(function (p) {
|
||||
return !isPointOverlap(p, t0) && !isPointOverlap(p, t2);
|
||||
});
|
||||
|
||||
return [pResult, tResult];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function pushJoints(store, index, joints) {
|
||||
if (!store[index]) {
|
||||
store[index] = [];
|
||||
}
|
||||
|
||||
joints.forEach(function (p) {
|
||||
store[index].push(p);
|
||||
});
|
||||
}
|
||||
|
||||
function popJoints(store) {
|
||||
return Object.keys(store).map(function (key) {
|
||||
return {
|
||||
index: +key,
|
||||
points: store[key]
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将bezier曲线和直线,bezier曲线之间相交部分进行插值分段
|
||||
*
|
||||
* @param {Array} subjectPath 主路径
|
||||
* @param {Array} clipPath 剪切路径
|
||||
*/
|
||||
function interpolatePathCrossBezier(subjectPath, clipPath) {
|
||||
|
||||
var isSelfInterpolate = subjectPath === clipPath;
|
||||
var curPointSubject;
|
||||
var prevPointSubject;
|
||||
var nextPointSubject;
|
||||
var curPointClip;
|
||||
var prevPointClip;
|
||||
var nextPointClip;
|
||||
|
||||
// 记录贝塞尔曲线分割点
|
||||
var subjectJoints = {};
|
||||
var clipJoints = {};
|
||||
var clipSize;
|
||||
var result;
|
||||
|
||||
for (var i = 0, subjectSize = subjectPath.length, j; i < subjectSize; i++) {
|
||||
curPointSubject = subjectPath[i];
|
||||
prevPointSubject = i === 0 ? subjectPath[subjectSize - 1] : subjectPath[i - 1];
|
||||
nextPointSubject = i === subjectSize - 1 ? subjectPath[0] : subjectPath[i + 1];
|
||||
|
||||
for (j = 0, clipSize = clipPath.length; j < clipSize; j++) {
|
||||
curPointClip = clipPath[j];
|
||||
prevPointClip = j === 0 ? clipPath[clipSize - 1] : clipPath[j - 1];
|
||||
nextPointClip = j === clipSize - 1 ? clipPath[0] : clipPath[j + 1];
|
||||
|
||||
// 直线与bezier曲线相交
|
||||
if (curPointSubject.onCurve && nextPointSubject.onCurve && !curPointClip.onCurve
|
||||
&& !isSelfInterpolate) {
|
||||
if (result = getBezierSegmentJoint(
|
||||
prevPointClip, curPointClip, nextPointClip,
|
||||
curPointSubject, nextPointSubject)) {
|
||||
pushJoints(clipJoints, j, result);
|
||||
}
|
||||
}
|
||||
// bezier 曲线与直线
|
||||
else if (!curPointSubject.onCurve && curPointClip.onCurve && nextPointClip.onCurve) {
|
||||
if (result = getBezierSegmentJoint(
|
||||
prevPointSubject, curPointSubject, nextPointSubject,
|
||||
curPointClip, nextPointClip)) {
|
||||
pushJoints(subjectJoints, i, result);
|
||||
}
|
||||
}
|
||||
// bezier 曲线之间相交
|
||||
else if (!curPointSubject.onCurve && !curPointClip.onCurve && curPointSubject !== curPointClip) {
|
||||
if (result = getbezierCrossJoint(
|
||||
prevPointSubject, curPointSubject, nextPointSubject,
|
||||
prevPointClip, curPointClip, nextPointClip)) {
|
||||
pushJoints(subjectJoints, i, result[0]);
|
||||
pushJoints(clipJoints, j, result[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interpolatePathByJoint(subjectPath, popJoints(subjectJoints));
|
||||
// 如果不是自相交则对 clip path 进行插值
|
||||
if (subjectJoints !== clipJoints) {
|
||||
interpolatePathByJoint(clipPath, popJoints(clipJoints));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return interpolatePathCrossBezier;
|
||||
}
|
||||
);
|
||||
@@ -1,171 +0,0 @@
|
||||
/**
|
||||
* @file 路径分割
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var bezierQ2Split = require('math/bezierQ2Split');
|
||||
var getBezierQ2T = require('math/getBezierQ2T');
|
||||
|
||||
/**
|
||||
* 按索引号排序相交点,这里需要处理曲线段上有多个交点的问题
|
||||
*
|
||||
* @param {Array} path 路径
|
||||
* @param {Array} joint 交点数组
|
||||
* @return {Array} 排序后
|
||||
*/
|
||||
function sortJoint(path, joint) {
|
||||
|
||||
var length = path.length;
|
||||
|
||||
return joint.sort(function (p0, p1) {
|
||||
// 如果交点需要不相等,则按小到大排序
|
||||
if (p0.index !== p1.index) {
|
||||
return p0.index - p1.index;
|
||||
}
|
||||
|
||||
// 相等,则同一段上有多个交点,按照与原点距离排序
|
||||
var cur = path[p0.index];
|
||||
var next = p0.index === length - 1 ? path[0] : path[p0.index + 1];
|
||||
|
||||
// 直线
|
||||
if (cur.onCurve && next.onCurve) {
|
||||
return Math.pow(p0.x - cur.x, 2) + Math.pow(p0.y - cur.y, 2)
|
||||
- (Math.pow(p1.x - cur.x, 2) + Math.pow(p1.y - cur.y, 2));
|
||||
}
|
||||
else if (!cur.onCurve) {
|
||||
var prev = p0.index === 0 ? path[length - 1] : path[p0.index - 1];
|
||||
var t1 = getBezierQ2T(prev, cur, next, p0);
|
||||
var t2 = getBezierQ2T(prev, cur, next, p1);
|
||||
return t1 === t2 ? 0 : t1 < t2 ? -1 : 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 分割路径
|
||||
*
|
||||
* @param {Array} path 路径
|
||||
* @param {Array} joint 分割点数组
|
||||
* joint结构
|
||||
* {
|
||||
* x: , // x坐标
|
||||
* y: , //y坐标
|
||||
* index: // 交点的线段起始点索引
|
||||
* }
|
||||
* @param {string} indexProp 索引号
|
||||
* @return {Array} 分割后的路径集合
|
||||
*/
|
||||
function pathSplit(path, joint) {
|
||||
joint = sortJoint(path, joint);
|
||||
|
||||
var jointOffset = 0; // 用来标记插入点产生的偏移
|
||||
var i;
|
||||
var l;
|
||||
|
||||
// 插入分割点
|
||||
for (i = 0, l = joint.length; i < l; i++) {
|
||||
|
||||
var length = path.length;
|
||||
var p = joint[i];
|
||||
p.index += jointOffset;
|
||||
var cur = p.index;
|
||||
var next = cur === length - 1 ? 0 : cur + 1;
|
||||
|
||||
// 直线
|
||||
if (path[cur].onCurve && path[next].onCurve) {
|
||||
|
||||
// 在开始点相交
|
||||
if (Math.abs(path[cur].x - p.x) < 0.001 && Math.abs(path[cur].y - p.y) < 0.001) {
|
||||
p.index = cur;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 在结束点相交
|
||||
if (Math.abs(path[next].x - p.x) < 0.001 && Math.abs(path[next].y - p.y) < 0.001) {
|
||||
p.index = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
path.splice(cur + 1, 0, {
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
onCurve: true
|
||||
});
|
||||
p.index = cur + 1;
|
||||
jointOffset++;
|
||||
}
|
||||
|
||||
// 贝塞尔开始点,插入2个节点
|
||||
else if (!path[cur].onCurve) {
|
||||
|
||||
var prev = cur === 0 ? length - 1 : cur - 1;
|
||||
|
||||
// 在开始点相交
|
||||
if (Math.abs(path[prev].x - p.x) < 0.001 && Math.abs(path[prev].y - p.y) < 0.001) {
|
||||
p.index = prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 在结束点相交
|
||||
if (Math.abs(path[next].x - p.x) < 0.001 && Math.abs(path[next].y - p.y) < 0.001) {
|
||||
p.index = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
var bezierArray = bezierQ2Split(path[prev], path[cur], path[next], p);
|
||||
|
||||
if (!bezierArray) {
|
||||
throw 'can\'t find bezier split point';
|
||||
}
|
||||
|
||||
path.splice(cur, 1,
|
||||
bezierArray[0][1],
|
||||
{
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
onCurve: true
|
||||
},
|
||||
bezierArray[1][1]
|
||||
);
|
||||
|
||||
p.index = cur + 1;
|
||||
jointOffset += 2;
|
||||
|
||||
}
|
||||
else {
|
||||
throw 'joint incorrect';
|
||||
}
|
||||
}
|
||||
|
||||
// 这里需要重新筛选排序
|
||||
joint.sort(function (p0, p1) {
|
||||
return p0.index - p1.index;
|
||||
});
|
||||
|
||||
// 分割曲线
|
||||
var splitedPaths = [];
|
||||
var start;
|
||||
var end;
|
||||
for (i = 0, l = joint.length - 1; i < l; i++) {
|
||||
start = joint[i];
|
||||
end = joint[i + 1];
|
||||
splitedPaths.push(path.slice(start.index, end.index + 1));
|
||||
}
|
||||
|
||||
// 闭合轮廓
|
||||
start = end;
|
||||
end = joint[0];
|
||||
splitedPaths.push(path.slice(start.index).concat(path.slice(0, end.index + 1)));
|
||||
|
||||
return splitedPaths.filter(function (path) {
|
||||
return path.length > 2;
|
||||
});
|
||||
}
|
||||
|
||||
return pathSplit;
|
||||
}
|
||||
);
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* @file 路径相交关系
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function (require) {
|
||||
return {
|
||||
intersect: 0, // 相交
|
||||
join: 1, // 合并
|
||||
differ: 2, // 不同
|
||||
tangency: 3 // 相切
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* @file 曲线段重新转换成bezier曲线
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var util = require('graphics/util');
|
||||
var getPointHash = util.getPointHash;
|
||||
|
||||
|
||||
/**
|
||||
* 曲线段转bezier曲线
|
||||
* @param {Array} paths 路径组
|
||||
* @param {Object} bezierHash 待转换的点集合
|
||||
* @return {Array} 转换后的路径
|
||||
*/
|
||||
function segment2Bezier(paths, bezierHash) {
|
||||
|
||||
// 重新转换成曲线路径
|
||||
for (var i = 0, l = paths.length, j, jl; i < l; i++) {
|
||||
var path = paths[i];
|
||||
// 寻找第一个插值点
|
||||
var startIndex;
|
||||
for (j = 0, jl = path.length; j < jl; j++) {
|
||||
var start = bezierHash[getPointHash(path[j])];
|
||||
if (start) {
|
||||
if (j + 8 < jl) {
|
||||
if (start === bezierHash[getPointHash(path[j + 8])]) {
|
||||
startIndex = j;
|
||||
}
|
||||
else {
|
||||
startIndex = j - 8 > 0 ? j - 8 : jl + j - 8;
|
||||
}
|
||||
}
|
||||
else {
|
||||
startIndex = j - 8 > 0 ? j - 8 : jl + j - 8;
|
||||
if (start !== bezierHash[getPointHash(path[startIndex])]) {
|
||||
startIndex = j;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (startIndex > 0) {
|
||||
path = [].concat(path.slice(startIndex)).concat(path.slice(0, startIndex));
|
||||
}
|
||||
|
||||
// 移除插值点
|
||||
for (j = 0; j < path.length; j++) {
|
||||
var point = bezierHash[getPointHash(path[j])];
|
||||
if (point) {
|
||||
path.splice(j, 9, point);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
paths[i] = path;
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
return segment2Bezier;
|
||||
}
|
||||
);
|
||||
74
src/graphics/pathBoolean.js
Normal file
74
src/graphics/pathBoolean.js
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @file 路径的布尔操作,使用paper.js进行路径操作
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
define(function (require) {
|
||||
var contours2svg = require('fonteditor-core/ttf/util/contours2svg');
|
||||
var path2contours = require('fonteditor-core/ttf/svg/path2contours');
|
||||
var paper = require('paper');
|
||||
|
||||
var RELATION = {
|
||||
intersect: 0, // 相交
|
||||
join: 1, // 合并
|
||||
differ: 2, // 不同
|
||||
tangency: 3 // 相切
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径布尔操作
|
||||
*
|
||||
* @param {Array} paths 路径集合
|
||||
* @param {number} relation 路径关系
|
||||
* @return {Array} 操作后结果
|
||||
*/
|
||||
function pathBoolean(paths, relation) {
|
||||
if (paths.length < 2) {
|
||||
return paths;
|
||||
}
|
||||
initPaper();
|
||||
|
||||
// 设置最后一个contour为切分路径
|
||||
var subject = getPath(paths.slice(0, paths.length - 1));
|
||||
var clipper = getPath(paths.slice(paths.length - 1));
|
||||
var resultPath;
|
||||
if (relation === RELATION.intersect) {
|
||||
resultPath = subject.intersect(clipper);
|
||||
}
|
||||
else if (relation === RELATION.join) {
|
||||
resultPath = subject.unite(clipper);
|
||||
}
|
||||
else if (relation === RELATION.differ) {
|
||||
resultPath = subject.subtract(clipper);
|
||||
}
|
||||
else if (relation === RELATION.tangency) {
|
||||
resultPath = subject.exclude(clipper);
|
||||
}
|
||||
|
||||
var contours = resultPath ? getContours(resultPath) : paths;
|
||||
paper.clear();
|
||||
return contours;
|
||||
}
|
||||
|
||||
pathBoolean.Relation = RELATION;
|
||||
|
||||
return pathBoolean;
|
||||
});
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
* @file 求路径的合并
|
||||
* 利用插值将曲线转换成直线,求解后再转换成曲线
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var Clipper = require('./join/Clipper');
|
||||
var Relation = require('./join/relation');
|
||||
var pathUtil = require('./pathUtil');
|
||||
var interpolate = pathUtil.interpolate;
|
||||
var deInterpolate = pathUtil.deInterpolate;
|
||||
|
||||
var util = require('graphics/util');
|
||||
var ceilPoint = util.ceilPoint;
|
||||
|
||||
var interpolatePathCrossBezier = require('./join/interpolatePathCrossBezier');
|
||||
var bezier2Segment = require('./join/bezier2Segment');
|
||||
var segment2Bezier = require('./join/segment2Bezier');
|
||||
var reducePath = require('./reducePath');
|
||||
|
||||
/**
|
||||
* 求路径交集、并集、差集
|
||||
*
|
||||
* @param {Array} paths 路径集合
|
||||
* @param {number} relation 关系
|
||||
* @return {Array} 合并后的路径
|
||||
*/
|
||||
function pathJoin(paths, relation) {
|
||||
if (paths.length === 1) {
|
||||
if (relation === Relation.intersect) {
|
||||
return [];
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
var i;
|
||||
var l;
|
||||
// 对路径进行插值,求舍入
|
||||
for (i = 0, l = paths.length; i < l; i++) {
|
||||
paths[i].forEach(ceilPoint);
|
||||
paths[i] = interpolate(paths[i]);
|
||||
}
|
||||
|
||||
// 计算bezier、直线的交点,分割bezier曲线
|
||||
for (i = 0, l = paths.length; i < l; i++) {
|
||||
for (var j = i; j < l; j++) {
|
||||
interpolatePathCrossBezier(paths[i], paths[j]);
|
||||
}
|
||||
}
|
||||
|
||||
var bezierHash = {};
|
||||
|
||||
// 对曲线使用线段拟合,clipper求路径关系
|
||||
for (i = 0, l = paths.length; i < l; i++) {
|
||||
paths[i] = bezier2Segment(paths[i], bezierHash);
|
||||
}
|
||||
|
||||
var clipper = new Clipper();
|
||||
clipper.addSubject(paths[0]);
|
||||
|
||||
for (i = 1, l = paths.length; i < l; i++) {
|
||||
// 非相交可以不需要clip路径,相交则把最后一个路径作为相交路径
|
||||
if (relation === Relation.intersect || relation === Relation.tangency) {
|
||||
clipper.addClip(paths[i]);
|
||||
}
|
||||
else {
|
||||
clipper.addSubject(paths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
paths = clipper.execute(relation);
|
||||
if (Object.keys(bezierHash).length) {
|
||||
paths = segment2Bezier(paths, bezierHash);
|
||||
}
|
||||
|
||||
return paths.filter(function (path) {
|
||||
return path.length > 2;
|
||||
}).map(function (path) {
|
||||
return reducePath(deInterpolate(path)).reverse();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
pathJoin.Relation = Relation;
|
||||
|
||||
return pathJoin;
|
||||
}
|
||||
);
|
||||
@@ -6,17 +6,6 @@
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var getSegmentPathJoint = require('./join/getSegmentPathJoint');
|
||||
var pathSplit = require('./join/pathSplit');
|
||||
var relation = require('./join/relation');
|
||||
|
||||
var util = require('./pathUtil');
|
||||
var interpolate = util.interpolate;
|
||||
var deInterpolate = util.deInterpolate;
|
||||
|
||||
var pathJoin = require('./pathJoin');
|
||||
|
||||
|
||||
/**
|
||||
* 线段切割路径
|
||||
*
|
||||
@@ -26,48 +15,7 @@ define(
|
||||
* @return {Array|false} 切割后路径或者false
|
||||
*/
|
||||
function pathSplitBySegment(paths, p0, p1) {
|
||||
|
||||
var iterSplitPath = function (p) {
|
||||
p.index = p.index1;
|
||||
return p;
|
||||
};
|
||||
|
||||
var leftSide = [];
|
||||
var rightSide = [];
|
||||
var leftPaths = [];
|
||||
var result;
|
||||
|
||||
for (var i = 0, l = paths.length, j, jl; i < l; i++) {
|
||||
var path = interpolate(paths[i]);
|
||||
result = getSegmentPathJoint(path, p0, p1);
|
||||
|
||||
if (result) {
|
||||
var splitedPaths = pathSplit(path, result.map(iterSplitPath));
|
||||
// 将分割后的路径分为左右两组
|
||||
for (j = 0, jl = splitedPaths.length; j < jl; j++) {
|
||||
var p2 = splitedPaths[j][1];
|
||||
|
||||
// 根据路径矢量关系确定点在左边还是右边
|
||||
if ((p0.x - p2.x) * (p1.y - p2.y) - (p0.y - p2.y) * (p1.x - p2.x) > 0) {
|
||||
leftSide.push(splitedPaths[j]);
|
||||
}
|
||||
else {
|
||||
rightSide.push(splitedPaths[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
leftPaths.push(paths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 组合左右两侧的曲线段
|
||||
result = pathJoin(leftSide, relation.join).concat(pathJoin(rightSide, relation.join));
|
||||
result = leftPaths.concat(result);
|
||||
|
||||
return result.map(function (path) {
|
||||
return deInterpolate(path);
|
||||
});
|
||||
return paths;
|
||||
}
|
||||
|
||||
return pathSplitBySegment;
|
||||
|
||||
Reference in New Issue
Block a user