path split by segment
This commit is contained in:
@@ -126,7 +126,7 @@ define(
|
||||
var bound = computeBoundingBox.computePath(shapes[i].points);
|
||||
// 判断是否相交
|
||||
if (isBoundingBoxSegmentCross(bound, p0, p1)) {
|
||||
shapesCross.push(shapes);
|
||||
shapesCross.push(shapes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
102
src/graphics/join/interpolatePathByJoint.js
Normal file
102
src/graphics/join/interpolatePathByJoint.js
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
);
|
||||
@@ -9,52 +9,9 @@ define(
|
||||
|
||||
var isBezierSegmentCross = require('graphics/isBezierSegmentCross');
|
||||
var isBezierCross = require('graphics/isBezierCross');
|
||||
var bezierQ2Split = require('math/bezierQ2Split');
|
||||
var getBezierQ2Point = require('math/getBezierQ2Point');
|
||||
var getBezierQ2T = require('math/getBezierQ2T');
|
||||
var interpolatePathByJoint = require('graphics/join/interpolatePathByJoint');
|
||||
var util = require('graphics/util');
|
||||
var isPointOverlap = util.isPointOverlap;
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 线段分割贝塞尔曲线
|
||||
@@ -123,29 +80,13 @@ define(
|
||||
});
|
||||
}
|
||||
|
||||
function splitBezier(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];
|
||||
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)));
|
||||
});
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将bezier曲线和直线,bezier曲线之间相交部分进行插值分段
|
||||
* @param {Array} subjectPath 主路径
|
||||
* @param {Array} clipPath 剪切路径
|
||||
* @return {Array} 相交的点集
|
||||
*/
|
||||
function interpolatePathJoint (subjectPath, clipPath) {
|
||||
function interpolatePathCrossBezier (subjectPath, clipPath) {
|
||||
|
||||
var isSelfInterpolate = subjectPath === clipPath;
|
||||
var curPointSubject;
|
||||
@@ -202,15 +143,15 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
splitBezier(subjectPath, popJoints(subjectJoints));
|
||||
interpolatePathByJoint(subjectPath, popJoints(subjectJoints));
|
||||
// 如果不是自相交则对 clip path 进行插值
|
||||
if (subjectJoints !== clipJoints) {
|
||||
splitBezier(clipPath, popJoints(clipJoints));
|
||||
interpolatePathByJoint(clipPath, popJoints(clipJoints));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return interpolatePathJoint;
|
||||
return interpolatePathCrossBezier;
|
||||
}
|
||||
);
|
||||
@@ -20,8 +20,9 @@ define(
|
||||
|
||||
var util = require('graphics/util');
|
||||
var ceilPoint = util.ceilPoint;
|
||||
var getPointHash = util.getPointHash;
|
||||
|
||||
var interpolatePathJoint = require('./join/interpolatePathJoint');
|
||||
var interpolatePathCrossBezier = require('./join/interpolatePathCrossBezier');
|
||||
|
||||
|
||||
var getBezierQ2Point = require('math/getBezierQ2Point');
|
||||
@@ -63,11 +64,6 @@ define(
|
||||
}
|
||||
|
||||
|
||||
function getPointHash(p) {
|
||||
return Math.floor(7 * Math.floor(p.x * 100) + 31 * Math.floor(p.y * 100));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 求路径交集、并集、差集
|
||||
*
|
||||
@@ -97,7 +93,7 @@ define(
|
||||
// 计算bezier、直线的交点,分割bezier曲线
|
||||
for (i = 0, l = paths.length; i < l; i++) {
|
||||
for (var j = i; j < l; j++) {
|
||||
interpolatePathJoint(paths[i], paths[j]);
|
||||
interpolatePathCrossBezier(paths[i], paths[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var computeBoundingBox = require('./computeBoundingBox');
|
||||
var getSegmentPathJoint = require('./join/getSegmentPathJoint');
|
||||
var pathSplit = require('./join/pathSplit');
|
||||
var isBoundingBoxSegmentCross = require('./isBoundingBoxSegmentCross');
|
||||
var util = require('./pathUtil');
|
||||
var interpolate = util.interpolate;
|
||||
var deInterpolate = util.deInterpolate;
|
||||
var util = require('graphics/util');
|
||||
var isPointOverlap = util.isPointOverlap;
|
||||
var getPointHash = util.getPointHash;
|
||||
|
||||
/**
|
||||
* 线段切割路径
|
||||
@@ -30,41 +31,88 @@ define(
|
||||
|
||||
var i = 0;
|
||||
var l = paths.length;
|
||||
var leftSide = [];
|
||||
var rightSide = [];
|
||||
var jointArray = [];
|
||||
|
||||
for (; i < l; i++) {
|
||||
paths[i] = interpolate(paths[i]);
|
||||
var result = getSegmentPathJoint(paths[i], p0, p1);
|
||||
console.log(result);
|
||||
var path = interpolate(paths[i]);
|
||||
var result = getSegmentPathJoint(path, p0, p1);
|
||||
if (result) {
|
||||
|
||||
var splitedPaths = pathSplit(path, result.map(function (p) {
|
||||
|
||||
p.from = i;
|
||||
p.index = p.index1;
|
||||
|
||||
var cur = path[p.index];
|
||||
var next = path[p.index === path.length - 1 ? 0 : p.index + 1];
|
||||
// bezier曲线起始点
|
||||
if (!cur.onCurve) {
|
||||
cur = path[p.index === 0 ? path.length - 1 : p.index - 1];
|
||||
next = path[p.index === path.length - 1 ? 0 : p.index + 1];
|
||||
}
|
||||
// 求zCount
|
||||
p.zCount = (p.zCount || 0)
|
||||
+ (
|
||||
(p.x - cur.x > 0 && p.x - next.x < 0)
|
||||
|| Math.abs(p.x - cur.x) < 0.001 && (p.y - cur.y > 0 && p.y - next.y < 0)
|
||||
? -1 : 1
|
||||
);
|
||||
jointArray.push(p);
|
||||
|
||||
return p;
|
||||
}));
|
||||
|
||||
// 将分割后的路径分为左右两组
|
||||
// http://blog.csdn.net/modiz/article/details/9928955
|
||||
splitedPaths.forEach(function (path) {
|
||||
var p2 = path[1];
|
||||
if ((p0.x - p2.x) * (p1.y - p2.y) - (p0.y - p2.y) * (p1.x - p2.x) > 0) {
|
||||
leftSide.push(path);
|
||||
}
|
||||
else {
|
||||
rightSide.push(path);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 有交点
|
||||
// if (result && result.length > 1) {
|
||||
if (jointArray.length <= 1) {
|
||||
return paths;
|
||||
}
|
||||
|
||||
// var splitedPaths = pathSplit(path, result.map(function (p) {
|
||||
// p.index = p.index1;
|
||||
// return p;
|
||||
// }));
|
||||
// 交点按照距离原点顺序排序
|
||||
if (p0.x === p1.x) {
|
||||
jointArray = jointArray.sort(function (a, b) {
|
||||
return a.y - b.y;
|
||||
});
|
||||
}
|
||||
else {
|
||||
jointArray = jointArray.sort(function (a, b) {
|
||||
return a.x - b.x;
|
||||
});
|
||||
}
|
||||
|
||||
//console.log(jointArray);
|
||||
|
||||
// // 轮廓为凹的需要寻找可以合并的轮廓
|
||||
// var last = splitedPaths.length - 1;
|
||||
// splitedPaths[last].direction = util.isClockWise(splitedPaths[last]);
|
||||
// for (var i = last - 1; i > 0; i--) {
|
||||
// splitedPaths[i].direction = util.isClockWise(splitedPaths[i]);
|
||||
// if (splitedPaths[i].direction !== splitedPaths[i + 1].direction) {
|
||||
// var prevPrev = i === last - 1 ? 0 : i + 2;
|
||||
// var newPath = splitedPaths[prevPrev].concat(splitedPaths[i]);
|
||||
// newPath.direction = splitedPaths[i + 1].direction;
|
||||
// 按照 no-zero 规则获取交点线段
|
||||
var start = jointArray[0];
|
||||
var zCount = start.zCount;
|
||||
var jointSegment = [];
|
||||
for (i = 1, l = jointArray.length; i < l; i++) {
|
||||
zCount += jointArray[i].zCount;
|
||||
if (!zCount) {
|
||||
jointSegment.push([start, jointArray[i]]);
|
||||
start = jointArray[++i];
|
||||
zCount = start ? start.zCount : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// if (prevPrev === 0) {
|
||||
// splitedPaths[0] = newPath;
|
||||
// splitedPaths.splice(i, 1);
|
||||
// }
|
||||
// else {
|
||||
// splitedPaths[i] = newPath;
|
||||
// splitedPaths.splice(prevPrev, 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// TODO 组合左右两侧的曲线段
|
||||
console.log(jointSegment);
|
||||
console.log(leftSide);
|
||||
console.log(rightSide);
|
||||
|
||||
|
||||
return paths.map(function (path) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
define(
|
||||
function (require) {
|
||||
|
||||
var getPointHash = require('./util').getPointHash;
|
||||
|
||||
/**
|
||||
* 对路径进行插值,补全省略的点
|
||||
@@ -98,16 +99,6 @@ define(
|
||||
: zCount < 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取点的hash
|
||||
* @param {Object} p 点对象
|
||||
*
|
||||
* @return {number} 哈希值
|
||||
*/
|
||||
function getPointHash(p) {
|
||||
return Math.floor(7 * Math.floor(p.x * 100) + 31 * Math.floor(p.y * 100)) + (p.onCurve ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取路径哈希
|
||||
* @param {Array} path 路径数组
|
||||
@@ -119,7 +110,7 @@ define(
|
||||
var seed = 131;
|
||||
|
||||
path.forEach(function (p) {
|
||||
hash = 0x7FFFFFFF & (hash * seed + getPointHash(p));
|
||||
hash = 0x7FFFFFFF & (hash * seed + getPointHash(p) + (p.onCurve ? 1 : 0));
|
||||
});
|
||||
|
||||
return hash;
|
||||
@@ -150,7 +141,6 @@ define(
|
||||
deInterpolate: deInterpolate,
|
||||
isClockWise: isClockWise,
|
||||
removeOverlapPoints: removeOverlapPoints,
|
||||
getPointHash: getPointHash,
|
||||
getPathHash: getPathHash
|
||||
};
|
||||
}
|
||||
|
||||
@@ -85,11 +85,24 @@ define(
|
||||
return ceil(p0.x) === ceil(p1.x) && ceil(p0.y) === ceil(p1.y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取点的hash值
|
||||
*
|
||||
* @param {Object} p p
|
||||
* @param {Object} p1 p1
|
||||
* @return {number}
|
||||
*/
|
||||
function getPointHash(p) {
|
||||
return Math.floor(7 * Math.floor(p.x * 100) + 31 * Math.floor(p.y * 100));
|
||||
}
|
||||
|
||||
return {
|
||||
ceil: ceil,
|
||||
ceilPoint: ceilPoint,
|
||||
isPointInBound: isPointInBound,
|
||||
isPointOverlap: isPointOverlap
|
||||
isPointOverlap: isPointOverlap,
|
||||
getPointHash: getPointHash
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user