在坐标之间绘制多边形,防止相交

2024-01-05

JS小提琴 https://jsfiddle.net/8jpk4gr2/

我有一个通过鼠标点击填充的坐标数组canvas.

var pointsArray = [];

This array is push使用单击事件编辑 x 和 y 值。

pointsArray.push({x: xVal, y: yVal});

我迭代点数组并在当前点和前一个点之间画一条线。

function drawPolygon(points) {
    //check arguments for null values
    if(!points)
        return false;

    var i;
    for(i = 0; i < points.length; i++)
        drawLine(points[i-1], points[i]);

    //draw the final line
    drawLine(points[i-1], points[0]);
}

画线看起来像这样:

function drawLine(point1, point2) {
    //check arguments for null values
    if(!point1 || !point2)
        return false;

    context.beginPath();
    context.moveTo(point1.x, point1.y);
    context.lineTo(point2.x, point2.y);
    context.stroke();
}

不幸的是,根据用户点击的顺序,我可以让线条相交,这是我不想要的:https://i.stack.imgur.com/NefX5.png https://i.stack.imgur.com/NefX5.png我该如何解决这个问题?我的第一直觉告诉我按照从上到下、从左到右的顺序对点进行排序array然后画。


步骤 1:使用点的平均位置找到多边形的中心

该函数将在给定绘图中所有点的情况下找到中心,与顺序无关:

function findCenter(points) {

  var x = 0, y = 0, i, len = points.length;

  for (i = 0; i < len; i++) {
    x += points[i].x;
    y += points[i].y;
  }
  return {x: x / len, y: y / len};   // return average position
}

显示多边形中心点的演示

/**
 * Created by knguyen on 4/13/2015.
 */
var pointsArray = [];
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");

function Point(x, y) {
    this.x = x;
    this.y = y;
}

function drawDot(e) {
    var position = getMousePosition(canvas, e);
    posx = position.x;
    posy = position.y;

    storeCoordinate(posx, posy);

    context.fillStyle = "#F00";
    context.fillRect(posx, posy, 6, 6);
}

function getMousePosition(c, e) {
    var rect = canvas.getBoundingClientRect();
    return {x: e.clientX - rect.left, y: e.clientY - rect.top}
}
function storeCoordinate(xVal, yVal) {pointsArray.push(new Point(xVal, yVal))}

$("#solve").click(
    function() {
      var p = findCenter(pointsArray);
      context.fillStyle = "green";
      context.fillRect(p.x, p.y, 4, 4);
    }
);

function findCenter(points) {

  var x = 0, y = 0, i, len = points.length;

  for (i = 0; i < len; i++) {
    x += points[i].x;
    y += points[i].y;
  }
  return {x: x / len, y: y / len};   // return average position
}
#myCanvas {border: 1px solid #000}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="myCanvas" width="400" height="300" onclick="drawDot(event)"></canvas>
<div>
  <button type="button" class="btn btn-default" id="solve">Show center point</button>
</div>

步骤 2:根据角度对点进行排序

  • 扩展点对象以也采用角度参数。
  • 迭代点数组
  • 计算相对于中心点的角度
  • 根据角度对数组进行排序

要找到角度,只需计算相对于中心点的角度即可。

具体方法如下:

function findAngles(c, points) {

  var i, len = points.length, p, dx, dy;

  for (i = 0; i < len; i++) {
    p = points[i];
    dx = p.x - c.x;
    dy = p.y - c.y;
    p.angle = Math.atan2(dy, dx);
  }
}

然后,您必须使用自定义排序函数根据角度对点进行排序。只需使用标准sort()数组上的方法并提供您自己的函数,该函数将使用点对象的角度属性:

pointsArray.sort(function(a, b) {
  if (a.angle > b.angle) return 1;
  else if (a.angle < b.angle) return -1;
  return 0;
});

然后在所有点之间画一条线。

工作演示

var pointsArray = [];
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");

function Point(x, y) {
    this.x = x;
    this.y = y;
    this.angle = 0;
}

canvas.onclick = drawDot;
function drawDot(e) {
    var position = getMousePosition(canvas, e);
    posx = position.x;
    posy = position.y;
    storeCoordinate(posx, posy);
    context.fillStyle = "#F00";
    context.fillRect(posx-3, posy-3, 6, 6);
}

function getMousePosition(c, e) {
    var rect = canvas.getBoundingClientRect();
    return {x: e.clientX - rect.left, y: e.clientY - rect.top}
}
function storeCoordinate(xVal, yVal) {pointsArray.push(new Point(xVal, yVal))}

$("#solve").click(
    function() {

      // find center
      var cent = findCenter(pointsArray);
      context.fillStyle = "green";
      context.fillRect(cent.x-3, cent.y-3, 6, 6);
      
      // find angles
      findAngles(cent, pointsArray);
      
      // sort based on angle using custom sort
      pointsArray.sort(function(a, b) {
        return (a.angle >= b.angle) ? 1 : -1
      });
            
      // draw lines
      context.beginPath();
      context.moveTo(pointsArray[0].x, pointsArray[0].y);
      for(var i = 0; i < pointsArray.length; i++) {
        context.lineTo(pointsArray[i].x, pointsArray[i].y);
      }
      context.strokeStyle = "#00f";
      context.closePath();
      context.stroke();
    }
);

function findCenter(points) {
  var x = 0, y = 0, i, len = points.length;
  for (i = 0; i < len; i++) {
    x += points[i].x;
    y += points[i].y;
  }
  return {x: x / len, y: y / len};   // return average position
}

function findAngles(c, points) {
  var i, len = points.length, p, dx, dy;
  for (i = 0; i < len; i++) {
    p = points[i];
    dx = p.x - c.x;
    dy = p.y - c.y;
    p.angle = Math.atan2(dy, dx);
  }
}

$("#reset").click(
  function() {
      context.clearRect(0, 0, canvas.width, canvas.height); //clear the canvas
      pointsArray = []; //clear the array
  }
);
#myCanvas {border: 1px solid #000}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="myCanvas" width="400" height="300"></canvas>
<div><button id="solve">Draw Polygon</button><button id="reset">Reset</button></div>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在坐标之间绘制多边形,防止相交 的相关文章

随机推荐

  • jQuery XML 错误“请求的资源上不存在“Access-Control-Allow-Origin”标头。”

    我正在开发我的个人项目只是为了好玩 我想读取位于以下位置的 xml 文件 http www ecb europa eu stats eurofxref eurofxref daily xml http www ecb europa eu s
  • 在 Java 中预览 HTML [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 您知道哪些库 方法可以在 Swing 中进行一些基本的 HTML 表示 您能评论一下您的经历吗 一个好
  • 如何在 Scaladoc 中全局搜索方法?

    我是否有可能通过 scala 文档在全局范围内搜索类 特征或对象中的方法 示例 我有一个方法名称 但我不知道它属于哪个类 因此我可以在某些 scaladoc 搜索中键入它 它会向我显示包含给定名称的方法的类 PS 我本来会添加标签 scal
  • 插入创建新表

    我有两个大表 想要将所有列名 不是作为视图 合并到一个新表中 I 没有权限右键单击每个表并选择 CREATE TO SCRIPT 所以我想知道是否有一种方法可以将两个表插入到新表中而不指定列数据类型 SELECT top 0 INTO Ne
  • SQL Server 中的四舍五入

    我需要对 SQL Server 中最接近 2 个位置的一些数据类型数字进行四舍五入 Eg Input 123 10000000 Output 123 10 感谢致敬 Ismail 您需要将其转换 Select Convert numeric
  • 如何在已经居中对齐的元素周围添加元素?

    我创建了一个表单 其中一些文本元素垂直对齐 如下所示 它们使用 Flexbox 在页面上水平和垂直居中 my class display flex justify content center align items center flex
  • 在pdf c#中的另一个图像上添加图像水印

    All 我正在尝试使用 itextsharp 在 pdf 中添加图像水印 水印按预期出现在所有页面上 但其中已经有图像 我希望我的水印图像位于 pdf 上现有图像的顶部 我正在使用以下代码来添加图像 using Stream output
  • std::size_t 与 size_t 与 std::string::size_type

    哪里有size t当我没有包含任何东西时来自 总是假设是否合理size t std size t 我什么时候应该使用size type in std容器 string size type vector
  • Unity3D XML(-RPC) 和 C#

    我实际上是在这里回答我自己的问题 我一定是世界上唯一尝试这样做的人 但考虑到我花了大约一周的时间才解决这个问题 我想如果还有另一个人想在 Unity 中使用 XML RPC 我将为他们省去一周的麻烦 我想做的是与我们的游戏服务器之一对话以获
  • 使用 PHP API oauth2.0 的 Google 日历服务帐户 - 如何访问未共享的日历

    我在使用 Google 提供的 PHP 库读取日历事件时遇到问题 我想要阅读的日历不是公开共享的 但我想在我的服务器应用程序上阅读它们 尽管日历是与我共享的 但保存日历的帐户与我的帐户是分开的 我将其称为 API 帐户 根据 Google
  • 如何在flutter中访问另一个有状态小部件中一个有状态小部件中创建的对象

    我被困在我的项目中 我在 flutter 中创建了两个有状态的小部件作为两个不同的 dart 文件 现在 我必须在第二个小部件中访问第一个小部件中创建的对象的实例 但我不太确定在创建小部件时如何在 flutter 中执行此操作 我想到的一种
  • Hibernate多用户,动态变化

    从技术上讲 这里有两个问题 但紧密耦合 我在一个新项目中使用 Hibernate 它是POS http en wikipedia org wiki Point of sale项目 它使用Oracle数据库 我们决定使用 Hibernate
  • 如何使用 SLURM 通过 CUDA 在 GPU 网格上运行多个作业

    我一直致力于使用 CUDA 加快作业的处理时间 通常这会相当简单 但是我遇到了一个相当有趣的问题 我们使用 slurm 来安排我们的作业 通过添加 CUDA 代码并启用它的编译 它使单个作业时间减少了一半 当查看 GPU 上的负载时就会出现
  • 无法在 Visual Studio 2008/2010 中查看 WIX 项目类型

    我的计算机上安装了 Visual Studio 2008 2010 和 WIX37 msi WIX 3 7 但是 我无法在 Visual studio 2008 2010 中看到 WIX 项目类型 我需要安装额外的工具 插件吗 我的计算机上
  • 获取组件的实际宽度和高度

    我们在 JavaScript 中面临着一个相当可怕的问题 我们似乎都没有能力解决这个问题 我们如何获取 DOM 元素 包括子元素 整个盒模型等 的宽度和高度 而组件实际上并未显示在页面上 请记住 我正在寻找建议 即使答案不能完全回答问题 或
  • 如果 PHP 版本的条件忽略新代码

    所以我有一个需要在多个站点上运行的脚本 我有一个版本的脚本 它使用一些新的 PHP 5 3 函数进行了优化 但有些网站是 5 2 等 这段代码 if version compare PHP VERSION 5 3 0 gt 0 Do the
  • 如何找到 Azure 部署的暂存 URL?

    我已经将自动构建部署到 Azure 我想知道暂存 URL 理想情况下 我希望能够为其分配一个 DNS 这样我就不必在每次部署时都分发新的暂存 URL 否则 我希望能够找到暂存 URL 以便我可以自动分发它 有任何想法吗 假设您的自动化部署正
  • pip.conf 文件的位置

    我正在开发一个必须同时在 Windows 和 Linux 上运行的系统 它使用Python的venv与 Python 相关的所有内容的模块 我需要创建一个pip conf文件以激活我个人的取件 pip pip conf将其指向我们的内部 P
  • Telerik Radgrid GridDataItem.DataItem 更新时为空(OnUpdateCommand 处理程序)

    在 RadGrid 上处理 OnUpdateCommand 事件时 DataItem 为 null 我认为这也代表了行所代表的数据项 Radgrid 由 IList 填充 在处理程序中 代码如下所示 protected void rgAll
  • 在坐标之间绘制多边形,防止相交

    JS小提琴 https jsfiddle net 8jpk4gr2 我有一个通过鼠标点击填充的坐标数组canvas var pointsArray This array is push使用单击事件编辑 x 和 y 值 pointsArray