add path overlap

This commit is contained in:
kekee000 2014-11-28 00:04:29 +08:00
parent 2302a3773f
commit 247ad85643
6 changed files with 219 additions and 25 deletions

47
src/graphics/isOnPath.js Normal file
View File

@ -0,0 +1,47 @@
/**
* @file isOnPath.js
* @author mengke01
* @date
* @description
* 判断点是否在路径上
*/
define(
function(require) {
var pathIterator = require('./pathIterator');
var getBezierQ2T = require('math/getBezierQ2T');
/**
* 判断点是否在path上
*
* @param {Object} path path对象
* @param {Object} p 点对象
* @return {boolean|number} 是否在path上如果在的话返回起点索引号
*/
function isOnPath(path, p) {
var zCount = false;
pathIterator(path, function (c, p0, p1, p2, i) {
if (c === 'L') {
if (Math.abs((p.y - p0.y) * (p.x - p1.x) - (p.y - p1.y) * (p.x - p0.x)) <= 0.001) {
zCount = i;
return false;
}
}
else if(c === 'Q') {
if (false !== getBezierQ2T(p0, p1, p2, p)) {
zCount = i;
return false;
}
}
});
return zCount;
}
return isOnPath;
}
);

View File

@ -12,6 +12,7 @@ define(
var getPathJoint = require('./join/getPathJoint');
var isInsidePath = require('./isInsidePath');
var isBoundingBoxCross = require('./isBoundingBoxCross');
var util = require('./util');
/**
* 判断x轴射线是否穿过线段
@ -22,14 +23,13 @@ define(
*
* 2: path0 包含 path1
* 3: path1 包含 path0
* 4: 重叠
*/
function isPathCross(path0, path1, bound0, bound1) {
bound0 = bound0 || computeBoundingBox.computePath(path0);
bound1 = bound1 || computeBoundingBox.computePath(path1);
var boundCross = isBoundingBoxCross(bound0, bound1);
if (boundCross) {
if (isBoundingBoxCross(bound0, bound1)) {
var result = getPathJoint(path0, path1);
if (!result) {
// 0 包含 1
@ -42,7 +42,7 @@ define(
}
}
else {
return result;
return util.removeOverlap(result);
}
}

View File

@ -0,0 +1,100 @@
/**
* @file isPathOverlap.js
* @author mengke01
* @date
* @description
* 路径是否重叠
*/
define(
function(require) {
var computeBoundingBox = require('./computeBoundingBox');
var isOnPath = require('./isOnPath');
var isBoundingBoxCross = require('./isBoundingBoxCross');
var getPointHash = require('./util').getPointHash;
var pathIterator = require('./pathIterator');
var getPoint = require('math/getBezierQ2Point');
function isPathPointsOverlap(path0, path1) {
var hash = {};
path1.forEach(function(p) {
hash[getPointHash(p)] = true;
});
var overlapCount = 0;
path0.forEach(function(p) {
if (hash[getPointHash(p)]) {
overlapCount++;
}
});
return overlapCount === path0.length;
}
function isPathPointsOn(path0, path1) {
var zCount = 0;
var length = path1.length;
pathIterator(path0, function (c, p0, p1, p2) {
if (c === 'L') {
// 这里需要判断,直线重叠的情况
// TODO 需要判断是否是直线重叠,这里没有做判断
var i0 = isOnPath(path1, p0);
var i1 = isOnPath(path1, p1);
if (false === i0 || false === i1 || i0 !== i1) {
return false;
}
zCount++;
}
else if(c === 'Q') {
// 这里需要判断bezier曲线重叠的情况
// 需要判断是否是bezier曲线重叠这里没有做判断
var i0 = isOnPath(path1, p0);
var i1 = isOnPath(path1, p2);
var i2 = isOnPath(path1, getPoint(p0, p1, p2, 0.5));
if (false === i0 || false === i1 || false === i2) {
return false;
}
zCount++;
}
});
return zCount === path0.length;
}
/**
* 判断路径是否重叠需要注意的是路径应该是经过插值之后的否则会出现判断错误
*
* @return {boolean} 是否重叠
*/
function isPathOverlap(path0, path1, bound0, bound1) {
bound0 = bound0 || computeBoundingBox.computePath(path0);
bound1 = bound1 || computeBoundingBox.computePath(path1);
if (isBoundingBoxCross(bound0, bound1)) {
// 按点个数排下序
if (path1.length < path0.length) {
var tmp = path1;
path1 = path0;
path0 = tmp;
}
// 是否点重叠
if (isPathPointsOverlap(path0, path1) || isPathPointsOverlap(path1, path0)) {
return true;
}
// 是否点都在另一路径上
if (isPathPointsOn(path0, path1) || isPathPointsOn(path1, path0)) {
return true;
}
}
return false;
}
return isPathOverlap;
}
);

View File

@ -12,6 +12,7 @@ define(
var isPathCross = require('../isPathCross');
var isInsidePath = require('../isInsidePath');
//var isPathOverlap = require('../isPathOverlap');
var getBezierQ2Point = require('math/getBezierQ2Point');
var util = require('../util');
var Relation = require('./relation');
@ -27,13 +28,18 @@ define(
* @return {boolean} 是否相交
*/
function getPathCross(path, splitedPath) {
// if (isPathOverlap(splitedPath, path)) {
// return 0;
// }
var inPath = isInsidePath(
path,
splitedPath[1].onCurve
? splitedPath[1]
: getBezierQ2Point(splitedPath[0], splitedPath[1], splitedPath[2], 0.5)
);
return !!inPath;
return inPath ? 1 : 0;
}
/**
@ -67,7 +73,9 @@ define(
var inPath = false;
var partInPath = false;
var inPathBefore = -1;
// 求path0的分割曲线
var isOverlap = false;
// 判断path0的相交情况
splitedPaths0 = splitedPaths0.map(function(splitedPath) {
splitedPath.cross = getPathCross(path1, splitedPath);
@ -76,15 +84,13 @@ define(
inPath = true;
}
if (2 === splitedPath.cross) {
isOverlap = true;
}
// 这里需要判断整个曲线有相交区域,但是部分曲线只有交点没有相交轮廓的情况
if (inPathBefore === splitedPath.cross) {
if (false === inPathBefore) {
partInPath = true;
}
else {
// 这里需要修正相交边缘重叠的情况,不然组合路径的时候会出问题
// TODO
}
if (inPathBefore === splitedPath.cross && 0 === inPathBefore) {
partInPath = true;
}
@ -115,13 +121,22 @@ define(
console.warn('part cross');
}
else {
// 这里只需要判断第一个就可以知道曲线相交情况了
inPath = getPathCross(path0, splitedPaths1[0]);
splitedPaths1 = splitedPaths1.map(function(path) {
path.cross = inPath;
inPath = !inPath;
return path;
});
// 没有重叠的部分只需要判断第一个就可以知道曲线相交情况了
if (!isOverlap) {
inPath = getPathCross(path0, splitedPaths1[0]);
splitedPaths1 = splitedPaths1.map(function(path) {
path.cross = inPath;
inPath = !inPath;
return path;
});
}
else {
// 判断path1的相交情况
splitedPaths1 = splitedPaths1.map(function(splitedPath) {
splitedPath.cross = getPathCross(path0, splitedPath);
return splitedPath;
});
}
}
//异向的 combine 等于相切

View File

@ -90,7 +90,7 @@ define(
for (var i = 0; i < splitedPaths0.length; i++) {
var curPath = splitedPaths0[i];
var cross = curPath.cross; // 起始cross
var cross = !!curPath.cross; // 起始cross
var length = curPath.length;
// 对于求相切的情况,外轮廓不需要处理,内轮廓需要根据另一个轮廓的方向调整反向
@ -109,12 +109,13 @@ define(
var paths = nextHash[hashcode(end)];
// 选取异向
// 这里如果是相交或者合并的情况,不需要处理,如果是相切的情况则需要取反向的曲线
var p = paths[0];
if (relation === Relation.tangency && cross == p.cross && paths.length > 1) {
if (relation === Relation.tangency && cross == !!p.cross && paths.length > 1) {
p = paths[1];
}
// 选取异向
if (end.x == p[0].x && end.y == p[0].y) {
}
else {

View File

@ -110,11 +110,42 @@ define(
: zCount < 0 ? 1 : -1;
}
/**
* 获取点的hash
*
* @return {number} 哈希值
*/
function getPointHash(p) {
return (p.x * 31 + p.y) * 31 + (p.onCurve ? 1 : 0);
}
/**
* 移除重复点
*
* @param {Array} points 点集合
* @return {Array} 移除后点集合
*/
function removeOverlap(points) {
var hash = {};
var ret = [];
for (var i = 0, l = points.length; i < l ; i++) {
var hashcode = points[i].x * 31 + points[i].y;
if (!hash[hashcode]) {
ret.push(points[i]);
hash[hashcode] = 1;
}
}
return ret;
}
return {
ceil: ceil,
ceilPoint: ceilPoint,
isPointInBound: isPointInBound,
isClockWise: isClockWise
isClockWise: isClockWise,
removeOverlap: removeOverlap,
getPointHash: getPointHash
};
}
);