簡體   English   中英

算法創建正方形內n個角的多邊形(HTML5-Canvas)?

[英]Algorithm creating polygon of n corners inside a square (HTML5 - Canvas)?

考慮以下設置:

CSS:

div {
    position :absolute;
    top: 50px;
    left: 50px;
    height: 200px;
    width: 200px;
    border: 2px solid black;
}

HTML:

<div id="container">
    <canvas id="my-canvas"/>
</div>

現在,在#my-canvas內部,我希望能夠繪制一個始終具有任意數量的角且始終位於其一側(而不是其角之一)上的多邊形。 多邊形將“占據”的高度和寬度應始終等於其父代的高度和寬度(在本例中為200px X 200px),我們將假定它始終是一個正方形。

是否有一種標准算法可以實現這一目標(不使用任何JS庫)?

我猜最簡單的是在#my-container內部繪制一個具有4個角的多邊形,因為您基本上將創建一個相等大小的正方形:

var c = document.getElementById('my-canvas').getContext('2d');
var side = document.getElementById('container').clientHeight;
c.fillStyle = '#f00';
c.beginPath();
c.moveTo(0, 0);
c.lineTo(0, side);
c.lineTo(side, side);
c.lineTo(side, 0);
c.closePath();
c.fill();

但是,具有5個角或n個角的多邊形呢?

var corners = 5;
var c = document.getElementById('my-canvas').getContext('2d');
var side = (document.getElementById('container').clientHeight * 4) / corners;
c.fillStyle = '#f00';
c.beginPath();
c.moveTo(0, 0);
// ok the following is totally wrong, but I'm sure there is a loop involved and that the x & y
// should increment/decrement each time around in some way, relevant to the value of *side*
for (var i=0; i<corners; i++) {
   c.lineTo((side*i), side);
} 
c.closePath();
c.fill();

預先感謝您的任何幫助!

注意 :

我只對邊長相等的多邊形感興趣(我想這就是您所說的“常規”多邊形嗎?)。

由於我們處於HTML / CSS領域,因此允許的最小邊顯然是1px。 因此,這是唯一的限制。

我所指的多邊形的類型是在該圖像的左下角找到的多邊形。 顯然它們是“規則凸”類型的嗎? 抱歉,我不是數學家。

這實際上不是一個簡單的問題。 首先,讓我們少說些問題:

給定側長度S的平方和一個整數n≥3,確定最大長度L,使得與長度Ln條邊的規則,凸多邊形可以被構造成使得:

  1. 多邊形的一側位於正方形的一側;
  2. 多邊形包含在正方形內。

請注意,這並不需要多邊形觸及任何地方比對位於廣場一側的側其他方。 (盡管對於n > 3,並不難於表明還會有其他接觸點。)

一旦邊長為L ,就很容易構造多邊形本身。 讓我們先做(因為這將對第一部分有所幫助)。 從簡單的trig開始,多邊形的中心將是一個距離

h = L /(2⋅tan(π/ n ))

多邊形底邊中心的上方(根據對稱性)也將是正方形底邊中心的。 對於其余部分,我們假設多邊形的中心是坐標系的原點,其中+ X軸位於右側,而+ Y軸位於上方。 (請注意,我們的Y軸與通常的計算機圖形坐標系相反。)多邊形的半徑(從中心到每個頂點的距離)為

r = L /(2⋅sin(π/ n ))

讓我們將上面的方程式稱為1 我們將在最后參考。 頂點將由下式給出:

X I = R⋅COS(θ0 + 2⋅π⋅I / N)
ÿ = R⋅SIN(θ0 + 2⋅π⋅I / N)

其中,θ0是決定多邊形的旋轉的“相位角”。 我們希望旋轉使得多邊形的底邊是水平的。 如果我們希望第一個頂點( i = 0)是多邊形底部的正確頂點,那么我們應該使用

θ0 =-π/ 2

通過這種替換,我們的坐標方程簡化為:

X I = R⋅SIN(2⋅π⋅I / N)
YI = - R⋅COS(2⋅π⋅I / N)

為了將來參考,以上將是等式2 現在我們需要確定L。 我認為,將問題反過來更容易:對於給定的L ,最小的S是多少,使得邊長S的正方形可以包含多邊形,而一側包含多邊形的一側。 然后,我們可以縮放所有內容以匹配原始問題的給定平方。 但這很容易。 讓我們使用L =1。即使對於n ,多邊形的直徑d (多邊形上兩點之間的最大距離)為

d = 2⋅R = 1 / SIN(π/ N)(N偶數)

對於n個奇數,不難發現直徑是從底部一個頂點到多邊形頂部頂點的距離。 有了一點點結構(留給讀者)和余弦定律,結果就是:

d = sqrt([1 + cos(π/ n )] / [2⋅sin 2 (π/ n )])( n奇數)

在這兩種情況下,都很容易確定多邊形的至少一個直徑是水平的。 因此,包含多邊形的最小正方形的邊(多邊形底部位於正方形的底部)必須至少是直徑,並且(根據多邊形的直徑的定義)正方形永遠不必更大。 。

因為我們要縮放所有內容,以使正方形的邊測量給定的數量S ,所以我們最終得到:

L = S /

因此,構造多邊形的算法是首先確定L ,然后使用等式1來計算r ,最后使用等式2來計算頂點,頂點應按順序連接以形成多邊形。

簡單..

  • 將一個圓分成x個邊數,360 / x =邊角
  • 計算形狀的每個點
  • 計算一張臉的角度
  • 旋轉形狀,使臉平放在容器中
  • 重新縮放點以適合邊界

任何疑問..只需檢查下面的代碼

 //load data var c = document.getElementById('canvas').getContext('2d'); var width = document.getElementById('canvas').clientWidth; var height = document.getElementById('canvas').clientHeight; var corners = 5; //initial calculation var radius = 1; var angle = (Math.PI * 2) / corners; //build points var points = []; for (var i=0; i<corners; i++) { var a = angle * i; //sin and cos are swithced,point 0 is bottom one var x = (Math.sin(a)*radius); var y = (Math.cos(a)*radius); points.push({ x:x ,y:y }) } //get the angle of a side var sideangle = Math.atan2(points[1].y-points[0].y, points[1].x-points[0].x) //rotate point around bottom one var o = points[0]; for (var i=1; i<points.length; i++) { points[i] = { x:Math.cos(sideangle) * (points[i].x - ox) - Math.sin(sideangle) * (points[i].yo.y) + ox ,y:Math.sin(sideangle) * (points[i].x - ox) + Math.cos(sideangle) * (points[i].y - oy) + oy }; } //by this point the figure is "flat on the floor" lets measure its size var rect = {top:2,left:2,right:-2,bottom:-2}; for (var i=0; i<points.length; i++) { rect.top = Math.min(rect.top,points[i].y); rect.bottom = Math.max(rect.bottom,points[i].y); rect.left = Math.min(rect.left,points[i].x); rect.right = Math.max(rect.right,points[i].x); } rect.width = Math.abs(rect.right - rect.left); rect.height = Math.abs(rect.bottom - rect.top); //make points relative to top left of rect for (var i=0; i<points.length; i++) { points[i] = { x: points[i].x - rect.left ,y: points[i].y - rect.top }; } //lets scale and position the poly based on its rect var ratioX = width / rect.width var ratioY = height / rect.height var ratio = Math.min(ratioX, ratioY); for (var i=0; i<points.length; i++) { points[i] = { x: (points[i].x * ratio) ,y: (points[i].y * ratio) }; } //draw path c.beginPath(); c.moveTo(points[0].x, points[0].y); for (var i=1; i<points.length; i++) c.lineTo(points[i].x, points[i].y); c.closePath(); //draw c.strokeStyle='#f00' c.stroke(); c.fillStyle = '#f00'; //c.fill(); 
 canvas{ position :absolute; top: 50px; left: 50px; border: 2px solid black; } 
 <!--size must be defined as attribute--> <canvas width='300' height='200' id="canvas"/> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM