path split by segment

This commit is contained in:
kekee000
2015-02-27 23:59:19 +08:00
parent e5669926aa
commit 1b9a18fb82
7 changed files with 205 additions and 115 deletions

View File

@@ -126,7 +126,7 @@ define(
var bound = computeBoundingBox.computePath(shapes[i].points);
// 判断是否相交
if (isBoundingBoxSegmentCross(bound, p0, p1)) {
shapesCross.push(shapes);
shapesCross.push(shapes[i]);
}
}

View 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;
}
);

View File

@@ -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;
}
);

View File

@@ -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]);
}
}

View File

@@ -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) {

View File

@@ -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
};
}

View File

@@ -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
};
}
);