From 247ad8564311c143151bda396dc879c581aae7a3 Mon Sep 17 00:00:00 2001 From: kekee000 Date: Fri, 28 Nov 2014 00:04:29 +0800 Subject: [PATCH] add path overlap --- src/graphics/isOnPath.js | 47 +++++++++++++++ src/graphics/isPathCross.js | 8 +-- src/graphics/isPathOverlap.js | 100 +++++++++++++++++++++++++++++++ src/graphics/join/join2Path.js | 49 +++++++++------ src/graphics/join/pathCombine.js | 7 ++- src/graphics/util.js | 33 +++++++++- 6 files changed, 219 insertions(+), 25 deletions(-) create mode 100644 src/graphics/isOnPath.js create mode 100644 src/graphics/isPathOverlap.js diff --git a/src/graphics/isOnPath.js b/src/graphics/isOnPath.js new file mode 100644 index 0000000..d999069 --- /dev/null +++ b/src/graphics/isOnPath.js @@ -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; + } +); diff --git a/src/graphics/isPathCross.js b/src/graphics/isPathCross.js index d45b8b6..1671a05 100644 --- a/src/graphics/isPathCross.js +++ b/src/graphics/isPathCross.js @@ -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); } } diff --git a/src/graphics/isPathOverlap.js b/src/graphics/isPathOverlap.js new file mode 100644 index 0000000..09fb364 --- /dev/null +++ b/src/graphics/isPathOverlap.js @@ -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; + } +); diff --git a/src/graphics/join/join2Path.js b/src/graphics/join/join2Path.js index c7fcf35..931d781 100644 --- a/src/graphics/join/join2Path.js +++ b/src/graphics/join/join2Path.js @@ -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 等于相切 diff --git a/src/graphics/join/pathCombine.js b/src/graphics/join/pathCombine.js index 89d684f..4060809 100644 --- a/src/graphics/join/pathCombine.js +++ b/src/graphics/join/pathCombine.js @@ -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 { diff --git a/src/graphics/util.js b/src/graphics/util.js index 51bf952..3ea5658 100644 --- a/src/graphics/util.js +++ b/src/graphics/util.js @@ -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 }; } ); \ No newline at end of file