【问题标题】:Calculating Path (Polygon) of Path with Stroke - Javascript or Pseudocode用笔划计算路径的路径(多边形) - Javascript或伪代码
【发布时间】:2013-05-16 14:24:00
【问题描述】:

所以我有一个形成路径的点数组 (x, y)。我需要计算周围多边形的点。如果您熟悉 iOS,基本上是CGPathCreateCopyByStrokingPath。不幸的是,ObjC 不是一种选择。我需要在 Javascript、PHP 等中实现它。

    -------
    |  |  |
    |  |  |
    \  \  \
     \  \  \
      \  \  \
       \  \  \
        \  \  \-----------
         \  \----------- |
          \---------------

为糟糕的 ascii 艺术道歉。

我有一个 Javascript 的半工作版本,但我遇到了角落问题。

        function pathToPoly(points) {
            var numOfPoints = points.length;

            var fullPath = [];
            var leftPaths = [];
            var rightPaths = [];

            var pad = 20;

            for(var i=0; i<numOfPoints-1; i++) {
                var pointA = points[i];
                var pointB = points[i+1];

                var slope = (pointB.Y - pointA.Y) / (pointB.X - pointA.X);
                var inverseSlope = -1 / slope;
                var inverseAngle = Math.atan(inverseSlope);

                if(inverseAngle < 0) {
                    leftPaths.push({
                        X1: pointA.X - pad * Math.cos(inverseAngle),
                        Y1: pointA.Y - pad * Math.sin(inverseAngle),
                        X2: pointB.X - pad * Math.cos(inverseAngle),
                        Y2: pointB.Y - pad * Math.sin(inverseAngle)
                    });

                    rightPaths.push({
                        X1: pointA.X + pad * Math.cos(inverseAngle),
                        Y1: pointA.Y + pad * Math.sin(inverseAngle),
                        X2: pointB.X + pad * Math.cos(inverseAngle),
                        Y2: pointB.Y + pad * Math.sin(inverseAngle)
                    });
                } else {
                    rightPaths.push({
                        X1: pointA.X - pad * Math.cos(inverseAngle),
                        Y1: pointA.Y - pad * Math.sin(inverseAngle),
                        X2: pointB.X - pad * Math.cos(inverseAngle),
                        Y2: pointB.Y - pad * Math.sin(inverseAngle)
                    });

                    leftPaths.push({
                        X1: pointA.X + pad * Math.cos(inverseAngle),
                        Y1: pointA.Y + pad * Math.sin(inverseAngle),
                        X2: pointB.X + pad * Math.cos(inverseAngle),
                        Y2: pointB.Y + pad * Math.sin(inverseAngle)
                    });
                }

                if(drawSides) {
                    var leftSide = leftPaths[i];
                    var rightSide = rightPaths[i];

                    context.beginPath();

                    context.moveTo(leftSide.X1, leftSide.Y1);
                    context.lineTo(leftSide.X2, leftSide.Y2);

                    context.lineWidth = 1;
                    context.strokeStyle = 'yellow';
                    context.stroke();

                    context.beginPath();

                    context.moveTo(rightSide.X1, rightSide.Y1);
                    context.lineTo(rightSide.X2, rightSide.Y2);

                    context.lineWidth = 1;
                    context.strokeStyle = 'cyan';
                    context.stroke();
                }
            }

            for(var i=0; i<numOfPoints-1; i++) {
                var line1 = leftPaths[i];
                var line2 = leftPaths[i+1];

                fullPath.push({
                    X: line1.X1,
                    Y: line1.Y1
                });
                fullPath.push({
                    X: line1.X2,
                    Y: line1.Y2,
                });

                if(line2) {
                    fullPath.push({
                        X: line2.X1,
                        Y: line2.Y1,
                    });
                }
            }

            fullPath.push({
                X: leftPaths[numOfPoints-2].X2,
                Y: leftPaths[numOfPoints-2].Y2
            });

            for(var i=numOfPoints-2; i>=0; i--) {
                var line1 = rightPaths[i];
                var line2 = rightPaths[i-1];

                fullPath.push({
                    X: line1.X2,
                    Y: line1.Y2
                });

                fullPath.push({
                    X: line1.X1,
                    Y: line1.Y1,
                });
                if(line2) {
                    fullPath.push({
                        X: line2.X2,
                        Y: line2.Y2,
                    });
                }
            }

            fullPath.push({
                X: rightPaths[0].X1,
                Y: rightPaths[0].Y1
            });

            return fullPath;
        }

此代码在每个段的每一侧绘制平行线,并将它们连接起来。但是对于轮流,我的方法会创建一个无效的多边形。两侧“交换”并生成“反向”区域。并且能够计算面积对我的应用程序至关重要。

示例(我的声望太低,无法发布图片):蓝色效果很好,但红色效果不佳(注意右下角如何转,两边互换)。

![example](http://www.originalfunction.com/stackoverflow_16590082-1.png)

有什么建议吗?

【问题讨论】:

  • 我很好奇为什么需要计算输出点,而不是在某物上绘制多边形。你打算如何处理结果?
  • 我最终绘制了多边形,但我为多边形计算了额外的东西。这是针对我正在编程的游戏。
  • 好的。你能举个例子说明它是如何失败的(显示输入点、预期输出、实际输出)?
  • (我不保证我会有时间找出问题所在,但在我看来,如果你更明确地表明你试图解决什么失败,那么有人可以帮助你的可能性更大解决。)
  • @LarsH 谢谢。 atan2 确实解决了大部分问题!

标签: javascript graphics path polygon stroke


【解决方案1】:

当且仅当线条以锐角弯曲时(基于小样本)看起来它会失败,对吗?

我还没有彻底了解算法,只是一个有根据的猜测:我想知道您是否考虑到atan(slope) 有两个正确答案,而javascript atan() 函数可能没有返回您期望的答案(180 度偏离)?

atan2(y, x) 消除了这种歧义,如果你可以使用的话。

【讨论】:

    【解决方案2】:

    您可以使用Javascript Clipper 来偏移多边形(闭合路径)。要偏移折线(开放路径),您可以使用this code。有一个demo,您可以在其中测试偏移多边形。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 2019-12-09
      • 2020-09-22
      • 1970-01-01
      • 2015-03-06
      • 2012-10-05
      • 1970-01-01
      相关资源
      最近更新 更多