Adds #89 - Added delaunay Lua module

master
Yonaba 2015-09-22 10:11:37 +00:00
parent e7960051e3
commit bede9dd623
7 changed files with 2223 additions and 0 deletions

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Roland Y.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,111 @@
Delaunay
=====
[![Build Status](https://travis-ci.org/Yonaba/delaunay.png)](https://travis-ci.org/Yonaba/delaunay)
[![Coverage Status](https://coveralls.io/repos/Yonaba/delaunay/badge.png?branch=master)](https://coveralls.io/r/Yonaba/delaunay?branch=master)
[![License](http://img.shields.io/badge/Licence-MIT-brightgreen.svg)](LICENSE)
*delaunay* is a Lua module for [delaunay triangulation](http://en.wikipedia.org/wiki/Delaunay_triangulation) of a convex polygon.
##Download
###Git
````
git clone http://github.com/Yonaba/delaunay.git
````
###Archive
* [zip](https://github.com/Yonaba/delaunay/archive/delaunay-0.1-1.zip) | [tar.gz](https://github.com/Yonaba/delaunay/archive/delaunay-0.1-1.tar.gz) | [all](http://github.com/Yonaba/delaunay/tags)
###LuaRocks
````
luarocks install delaunay
````
###MoonRocks
````
luarocks install --server=http://rocks.moonscript.org/manifests/Yonaba delaunay
````
##Installation
Copy the file [delaunay.lua](http://raw.github.com/Yonaba/delaunay/master/delaunay.lua) inside your project folder,
call it with [require](http://pgl.yoyo.org/luai/i/require) function. It will return the `Delaunay` module, keeping safe the global environment.<br/>
##Usage
The module provides 3 classes: <br/>
* `Point`
* `Edge`
* `Triangle`
It also provides a single function named `triangulate`. This function accepts
a variable list (*vararg* `...`) of instances of class `Point`. Assuming those
points are the vertices of a convex polygon, it returns a table of instances of the class `Triangle` forming a *Delaunay triangulation* of the given polygon.
A basic code example:
```lua
local Delaunay = require 'Delaunay'
local Point = Delaunay.Point
-- Creating 10 random points
local points = {}
for i = 1, 10 do
points[i] = Point(math.random() * 100, math.random() * 100)
end
-- Triangulating de convex polygon made by those points
local triangles = Delaunay.triangulate(unpack(points))
-- Printing the results
for i, triangle in ipairs(triangles) do
print(triangle)
end
````
See the [documentation](http://yonaba.github.io/delaunay/doc) for more details.
##Testing
###Specification
This repository include unit tests. You can run them using [Telescope](https://github.com/norman/telescope) with the following command from the root foolder:
```
lua tsc -f specs/*
```
###Performance
You can run the random performance tests included with the following command from the root folder:
```lua
lua performance/bench.lua
````
##License
This work is under [MIT-LICENSE](http://www.opensource.org/licenses/mit-license.php).<br/>
Copyright (c) 2013 Roland Yonaba
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/Yonaba/delaunay/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

View File

@ -0,0 +1,801 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Delaunay module documentation</title>
<link rel="stylesheet" href="ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Delaunay (v0.1)</h1>
<h2>Contents</h2>
<ul>
<li><a href="#Class_Edge">Class Edge </a></li>
<li><a href="#Class_Point">Class Point </a></li>
<li><a href="#Class_Triangle">Class Triangle </a></li>
<li><a href="#Delaunay_module">Delaunay module </a></li>
</ul>
<h2>Scripts</h2>
<ul class="nowrap">
<li><strong>delaunay</strong></li>
</ul>
</div>
<div id="content">
<h1>Script <code>delaunay</code></h1>
<p>
<h2>Delaunay, Lua module for convex polygon triangulation</h2>
</p>
<p>
</p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2013</li>
<li><strong>License</strong>: MIT</li>
<li><strong>Author</strong>: Roland Yonaba</li>
</ul>
<h2><a href="#Class_Edge">Class Edge </a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Edge:new">Edge:new (p1, p2)</a></td>
<td class="summary">Creates a new <a href="index.html#Class_Edge">Edge</a> </td>
</tr>
<tr>
<td class="name" nowrap><a href="#Edge:same">Edge:same (otherEdge)</a></td>
<td class="summary">Test if <code>otherEdge</code> is similar to self.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Edge:length">Edge:length ()</a></td>
<td class="summary">Returns the length.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Edge:getMidPoint">Edge:getMidPoint ()</a></td>
<td class="summary">Returns the midpoint coordinates.</td>
</tr>
</table>
<h2><a href="#Class_Point">Class Point </a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Point:new">Point:new (x, y)</a></td>
<td class="summary">Creates a new <a href="index.html#Class_Point">Point</a> </td>
</tr>
<tr>
<td class="name" nowrap><a href="#Point:dist2">Point:dist2 (p)</a></td>
<td class="summary">Returns the square distance to another <a href="index.html#Class_Point">Point</a> .</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Point:dist">Point:dist (p)</a></td>
<td class="summary">Returns the distance to another <a href="index.html#Class_Point">Point</a> .</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Point:isInCircle">Point:isInCircle (cx, cy, r)</a></td>
<td class="summary">Checks if self lies into the bounds of a circle</td>
</tr>
</table>
<h2><a href="#Class_Triangle">Class Triangle </a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Triangle:new">Triangle:new (p1, p2, p3)</a></td>
<td class="summary">Creates a new <a href="index.html#Class_Triangle">Triangle</a> </td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:isCW">Triangle:isCW ()</a></td>
<td class="summary">Checks if the triangle is defined clockwise (sequence p1-p2-p3)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:isCCW">Triangle:isCCW ()</a></td>
<td class="summary">Checks if the triangle is defined counter-clockwise (sequence p1-p2-p3)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getSidesLength">Triangle:getSidesLength ()</a></td>
<td class="summary">Returns the length of the edges</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getCenter">Triangle:getCenter ()</a></td>
<td class="summary">Returns the coordinates of the center</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getCircumCircle">Triangle:getCircumCircle ()</a></td>
<td class="summary">Returns the coordinates of the circumcircle center and its radius</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getCircumCenter">Triangle:getCircumCenter ()</a></td>
<td class="summary">Returns the coordinates of the circumcircle center</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getCircumRadius">Triangle:getCircumRadius ()</a></td>
<td class="summary">Returns the radius of the circumcircle</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getArea">Triangle:getArea ()</a></td>
<td class="summary">Returns the area</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:inCircumCircle">Triangle:inCircumCircle (p)</a></td>
<td class="summary">Checks if a given point lies into the triangle circumcircle</td>
</tr>
</table>
<h2><a href="#Delaunay_module">Delaunay module </a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Delaunay">Delaunay</a></td>
<td class="summary">Delaunay module</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Delaunay.triangulate">Delaunay.triangulate (...)</a></td>
<td class="summary">Triangulates a set of given vertices</td>
</tr>
</table>
<br/>
<br/>
<h2><a name="Class_Edge"></a>Class Edge </h2>
<dl class="function">
<dt>
<a name = "Edge:new"></a>
<strong>Edge:new (p1, p2)</strong>
</dt>
<dd>
Creates a new <a href="index.html#Class_Edge">Edge</a>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">p1</span>
a <a href="index.html#Class_Point">Point</a>
</li>
<li><span class="parameter">p2</span>
a <a href="index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
a new <a href="index.html#Class_Edge">Edge</a>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> Delaunay = <span class="global">require</span> <span class="string">'Delaunay'</span>
<span class="keyword">local</span> Edge = Delaunay.Edge
<span class="keyword">local</span> Point = Delaunay.Point
<span class="keyword">local</span> e = Edge:new(Point(<span class="number">1</span>,<span class="number">1</span>), Point(<span class="number">2</span>,<span class="number">5</span>))
<span class="keyword">local</span> e = Edge(Point(<span class="number">1</span>,<span class="number">1</span>), Point(<span class="number">2</span>,<span class="number">5</span>)) <span class="comment">-- Alias to Edge.new
</span> <span class="global">print</span>(e) <span class="comment">-- print the edge members p1 and p2
</span></pre>
</ul>
</dd>
<dt>
<a name = "Edge:same"></a>
<strong>Edge:same (otherEdge)</strong>
</dt>
<dd>
Test if <code>otherEdge</code> is similar to self. It does not take into account the direction.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">otherEdge</span>
an <a href="index.html#Class_Edge">Edge</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<code>true</code> or <code>false</code>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> e1 = Edge(Point(<span class="number">1</span>,<span class="number">1</span>), Point(<span class="number">2</span>,<span class="number">5</span>))
<span class="keyword">local</span> e2 = Edge(Point(<span class="number">2</span>,<span class="number">5</span>), Point(<span class="number">1</span>,<span class="number">1</span>))
<span class="global">print</span>(e1:same(e2)) <span class="comment">--&gt; true
</span> <span class="global">print</span>(e1 == e2)) <span class="comment">--&gt; false, == operator considers the direction
</span></pre>
</ul>
</dd>
<dt>
<a name = "Edge:length"></a>
<strong>Edge:length ()</strong>
</dt>
<dd>
Returns the length.
<h3>Returns:</h3>
<ol>
the length of self
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> e = Edge(Point(), Point(<span class="number">10</span>,<span class="number">0</span>))
<span class="global">print</span>(e:length()) <span class="comment">--&gt; 10
</span></pre>
</ul>
</dd>
<dt>
<a name = "Edge:getMidPoint"></a>
<strong>Edge:getMidPoint ()</strong>
</dt>
<dd>
Returns the midpoint coordinates.
<h3>Returns:</h3>
<ol>
<li>
the x-coordinate of self midpoint</li>
<li>
the y-coordinate of self midpoint</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> e = Edge(Point(), Point(<span class="number">10</span>,<span class="number">0</span>))
<span class="global">print</span>(e:getMidPoint()) <span class="comment">--&gt; 5, 0
</span></pre>
</ul>
</dd>
</dl>
<h2><a name="Class_Point"></a>Class Point </h2>
<dl class="function">
<dt>
<a name = "Point:new"></a>
<strong>Point:new (x, y)</strong>
</dt>
<dd>
Creates a new <a href="index.html#Class_Point">Point</a>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">x</span>
the x-coordinate
</li>
<li><span class="parameter">y</span>
the y-coordinate
</li>
</ul>
<h3>Returns:</h3>
<ol>
a new <a href="index.html#Class_Point">Point</a>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> Delaunay = <span class="global">require</span> <span class="string">'Delaunay'</span>
<span class="keyword">local</span> Point = Delaunay.Point
<span class="keyword">local</span> p = Point:new(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> p = Point(<span class="number">1</span>,<span class="number">1</span>) <span class="comment">-- Alias to Point.new
</span> <span class="global">print</span>(p) <span class="comment">-- print the point members x and y
</span></pre>
</ul>
</dd>
<dt>
<a name = "Point:dist2"></a>
<strong>Point:dist2 (p)</strong>
</dt>
<dd>
Returns the square distance to another <a href="index.html#Class_Point">Point</a> .
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">p</span>
a <a href="index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
the square distance from self to <code>p</code>.
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2 = Point(), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="global">print</span>(p1:dist2(p2)) <span class="comment">--&gt; 2
</span></pre>
</ul>
</dd>
<dt>
<a name = "Point:dist"></a>
<strong>Point:dist (p)</strong>
</dt>
<dd>
Returns the distance to another <a href="index.html#Class_Point">Point</a> .
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">p</span>
a <a href="index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
the distance from self to <code>p</code>.
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2 = Point(), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="global">print</span>(p1:dist2(p2)) <span class="comment">--&gt; 1.4142135623731
</span></pre>
</ul>
</dd>
<dt>
<a name = "Point:isInCircle"></a>
<strong>Point:isInCircle (cx, cy, r)</strong>
</dt>
<dd>
Checks if self lies into the bounds of a circle
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">cx</span>
the x-coordinate of the circle center
</li>
<li><span class="parameter">cy</span>
the y-coordinate of the circle center
</li>
<li><span class="parameter">r</span>
the radius of the circle
</li>
</ul>
<h3>Returns:</h3>
<ol>
<code>true</code> or <code>false</code>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p = Point()
<span class="global">print</span>(p:isInCircle(<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>)) <span class="comment">--&gt; true
</span></pre>
</ul>
</dd>
</dl>
<h2><a name="Class_Triangle"></a>Class Triangle </h2>
<dl class="function">
<dt>
<a name = "Triangle:new"></a>
<strong>Triangle:new (p1, p2, p3)</strong>
</dt>
<dd>
Creates a new <a href="index.html#Class_Triangle">Triangle</a>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">p1</span>
a <a href="index.html#Class_Point">Point</a>
</li>
<li><span class="parameter">p2</span>
a <a href="index.html#Class_Point">Point</a>
</li>
<li><span class="parameter">p3</span>
a <a href="index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
a new <a href="index.html#Class_Triangle">Triangle</a>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> Delaunay = <span class="global">require</span> <span class="string">'Delaunay'</span>
<span class="keyword">local</span> Triangle = Delaunay.Triangle
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle:new(p1, p2, p3)
<span class="keyword">local</span> t = Triangle(p1, p2, p3) <span class="comment">-- Alias to Triangle.new
</span> <span class="global">print</span>(t) <span class="comment">-- print the triangle members p1, p2 and p3
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:isCW"></a>
<strong>Triangle:isCW ()</strong>
</dt>
<dd>
Checks if the triangle is defined clockwise (sequence p1-p2-p3)
<h3>Returns:</h3>
<ol>
<code>true</code> or <code>false</code>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">1</span>,<span class="number">1</span>), Point(<span class="number">2</span>,<span class="number">0</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:isCW()) <span class="comment">--&gt; true
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:isCCW"></a>
<strong>Triangle:isCCW ()</strong>
</dt>
<dd>
Checks if the triangle is defined counter-clockwise (sequence p1-p2-p3)
<h3>Returns:</h3>
<ol>
<code>true</code> or <code>false</code>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:isCCW()) <span class="comment">--&gt; true
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getSidesLength"></a>
<strong>Triangle:getSidesLength ()</strong>
</dt>
<dd>
Returns the length of the edges
<h3>Returns:</h3>
<ol>
<li>
the length of the edge p1-p2</li>
<li>
the length of the edge p2-p3</li>
<li>
the length of the edge p3-p1</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getSidesLength()) <span class="comment">--&gt; 2 1.4142135623731 1.4142135623731
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getCenter"></a>
<strong>Triangle:getCenter ()</strong>
</dt>
<dd>
Returns the coordinates of the center
<h3>Returns:</h3>
<ol>
<li>
the x-coordinate of the center</li>
<li>
the y-coordinate of the center</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getCenter()) <span class="comment">--&gt; 1 0.33333333333333
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getCircumCircle"></a>
<strong>Triangle:getCircumCircle ()</strong>
</dt>
<dd>
Returns the coordinates of the circumcircle center and its radius
<h3>Returns:</h3>
<ol>
<li>
the x-coordinate of the circumcircle center</li>
<li>
the y-coordinate of the circumcircle center</li>
<li>
the radius of the circumcircle</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getCircumCircle()) <span class="comment">--&gt; 1 0 1
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getCircumCenter"></a>
<strong>Triangle:getCircumCenter ()</strong>
</dt>
<dd>
Returns the coordinates of the circumcircle center
<h3>Returns:</h3>
<ol>
<li>
the x-coordinate of the circumcircle center</li>
<li>
the y-coordinate of the circumcircle center</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getCircumCenter()) <span class="comment">--&gt; 1 0
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getCircumRadius"></a>
<strong>Triangle:getCircumRadius ()</strong>
</dt>
<dd>
Returns the radius of the circumcircle
<h3>Returns:</h3>
<ol>
the radius of the circumcircle
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getCircumRadius()) <span class="comment">--&gt; 1
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getArea"></a>
<strong>Triangle:getArea ()</strong>
</dt>
<dd>
Returns the area
<h3>Returns:</h3>
<ol>
the area
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getArea()) <span class="comment">--&gt; 1
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:inCircumCircle"></a>
<strong>Triangle:inCircumCircle (p)</strong>
</dt>
<dd>
Checks if a given point lies into the triangle circumcircle
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">p</span>
a <a href="index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<code>true</code> or <code>false</code>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:inCircumCircle(Point(<span class="number">1</span>,-<span class="number">1</span>))) <span class="comment">--&gt; true
</span></pre>
</ul>
</dd>
</dl>
<h2><a name="Delaunay_module"></a>Delaunay module </h2>
<dl class="function">
<dt>
<a name = "Delaunay"></a>
<strong>Delaunay</strong>
</dt>
<dd>
Delaunay module
<h3>Fields:</h3>
<ul>
<li><span class="parameter">Point</span>
reference to the <a href="index.html#Class_Point">Point</a> class
</li>
<li><span class="parameter">Edge</span>
reference to the <a href="index.html#Class_Edge">Edge</a> class
</li>
<li><span class="parameter">Triangle</span>
reference to the <a href="index.html#Class_Triangle">Triangle</a> class
</li>
<li><span class="parameter">_VERSION</span>
the version of the current module
</li>
</ul>
</dd>
<dt>
<a name = "Delaunay.triangulate"></a>
<strong>Delaunay.triangulate (...)</strong>
</dt>
<dd>
Triangulates a set of given vertices
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">...</span>
a <code>vargarg</code> list of objects of type <a href="index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
a set of objects of type <a href="index.html#Class_Triangle">Triangle</a>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> Delaunay = <span class="global">require</span> <span class="string">'Delaunay'</span>
<span class="keyword">local</span> Point = Delaunay.Point
<span class="keyword">local</span> p1, p2, p3, p4 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>), Point(<span class="number">1</span>,-<span class="number">1</span>)
<span class="keyword">local</span> triangles = Delaunay.triangulate(p1, p2, p3, p4)
<span class="keyword">for</span> i = <span class="number">1</span>, #triangles <span class="keyword">do</span>
<span class="global">print</span>(triangles[i])
<span class="keyword">end</span></pre>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.0</a></i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,801 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Delaunay module documentation</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Delaunay (v0.1)</h1>
<h2>Contents</h2>
<ul>
<li><a href="#Class_Edge">Class Edge </a></li>
<li><a href="#Class_Point">Class Point </a></li>
<li><a href="#Class_Triangle">Class Triangle </a></li>
<li><a href="#Delaunay_module">Delaunay module </a></li>
</ul>
<h2>Scripts</h2>
<ul class="nowrap">
<li><strong>delaunay</strong></li>
</ul>
</div>
<div id="content">
<h1>Script <code>delaunay</code></h1>
<p>
<h2>Delaunay, Lua module for convex polygon triangulation</h2>
</p>
<p>
</p>
<h3>Info:</h3>
<ul>
<li><strong>Copyright</strong>: 2013</li>
<li><strong>License</strong>: MIT</li>
<li><strong>Author</strong>: Roland Yonaba</li>
</ul>
<h2><a href="#Class_Edge">Class Edge </a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Edge:new">Edge:new (p1, p2)</a></td>
<td class="summary">Creates a new <a href="../index.html#Class_Edge">Edge</a> </td>
</tr>
<tr>
<td class="name" nowrap><a href="#Edge:same">Edge:same (otherEdge)</a></td>
<td class="summary">Test if <code>otherEdge</code> is similar to self.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Edge:length">Edge:length ()</a></td>
<td class="summary">Returns the length.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Edge:getMidPoint">Edge:getMidPoint ()</a></td>
<td class="summary">Returns the midpoint coordinates.</td>
</tr>
</table>
<h2><a href="#Class_Point">Class Point </a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Point:new">Point:new (x, y)</a></td>
<td class="summary">Creates a new <a href="../index.html#Class_Point">Point</a> </td>
</tr>
<tr>
<td class="name" nowrap><a href="#Point:dist2">Point:dist2 (p)</a></td>
<td class="summary">Returns the square distance to another <a href="../index.html#Class_Point">Point</a> .</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Point:dist">Point:dist (p)</a></td>
<td class="summary">Returns the distance to another <a href="../index.html#Class_Point">Point</a> .</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Point:isInCircle">Point:isInCircle (cx, cy, r)</a></td>
<td class="summary">Checks if self lies into the bounds of a circle</td>
</tr>
</table>
<h2><a href="#Class_Triangle">Class Triangle </a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Triangle:new">Triangle:new (p1, p2, p3)</a></td>
<td class="summary">Creates a new <a href="../index.html#Class_Triangle">Triangle</a> </td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:isCW">Triangle:isCW ()</a></td>
<td class="summary">Checks if the triangle is defined clockwise (sequence p1-p2-p3)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:isCCW">Triangle:isCCW ()</a></td>
<td class="summary">Checks if the triangle is defined counter-clockwise (sequence p1-p2-p3)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getSidesLength">Triangle:getSidesLength ()</a></td>
<td class="summary">Returns the length of the edges</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getCenter">Triangle:getCenter ()</a></td>
<td class="summary">Returns the coordinates of the center</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getCircumCircle">Triangle:getCircumCircle ()</a></td>
<td class="summary">Returns the coordinates of the circumcircle center and its radius</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getCircumCenter">Triangle:getCircumCenter ()</a></td>
<td class="summary">Returns the coordinates of the circumcircle center</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getCircumRadius">Triangle:getCircumRadius ()</a></td>
<td class="summary">Returns the radius of the circumcircle</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:getArea">Triangle:getArea ()</a></td>
<td class="summary">Returns the area</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Triangle:inCircumCircle">Triangle:inCircumCircle (p)</a></td>
<td class="summary">Checks if a given point lies into the triangle circumcircle</td>
</tr>
</table>
<h2><a href="#Delaunay_module">Delaunay module </a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Delaunay">Delaunay</a></td>
<td class="summary">Delaunay module</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Delaunay.triangulate">Delaunay.triangulate (...)</a></td>
<td class="summary">Triangulates a set of given vertices</td>
</tr>
</table>
<br/>
<br/>
<h2><a name="Class_Edge"></a>Class Edge </h2>
<dl class="function">
<dt>
<a name = "Edge:new"></a>
<strong>Edge:new (p1, p2)</strong>
</dt>
<dd>
Creates a new <a href="../index.html#Class_Edge">Edge</a>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">p1</span>
a <a href="../index.html#Class_Point">Point</a>
</li>
<li><span class="parameter">p2</span>
a <a href="../index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
a new <a href="../index.html#Class_Edge">Edge</a>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> Delaunay = <span class="global">require</span> <span class="string">'Delaunay'</span>
<span class="keyword">local</span> Edge = Delaunay.Edge
<span class="keyword">local</span> Point = Delaunay.Point
<span class="keyword">local</span> e = Edge:new(Point(<span class="number">1</span>,<span class="number">1</span>), Point(<span class="number">2</span>,<span class="number">5</span>))
<span class="keyword">local</span> e = Edge(Point(<span class="number">1</span>,<span class="number">1</span>), Point(<span class="number">2</span>,<span class="number">5</span>)) <span class="comment">-- Alias to Edge.new
</span> <span class="global">print</span>(e) <span class="comment">-- print the edge members p1 and p2
</span></pre>
</ul>
</dd>
<dt>
<a name = "Edge:same"></a>
<strong>Edge:same (otherEdge)</strong>
</dt>
<dd>
Test if <code>otherEdge</code> is similar to self. It does not take into account the direction.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">otherEdge</span>
an <a href="../index.html#Class_Edge">Edge</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<code>true</code> or <code>false</code>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> e1 = Edge(Point(<span class="number">1</span>,<span class="number">1</span>), Point(<span class="number">2</span>,<span class="number">5</span>))
<span class="keyword">local</span> e2 = Edge(Point(<span class="number">2</span>,<span class="number">5</span>), Point(<span class="number">1</span>,<span class="number">1</span>))
<span class="global">print</span>(e1:same(e2)) <span class="comment">--&gt; true
</span> <span class="global">print</span>(e1 == e2)) <span class="comment">--&gt; false, == operator considers the direction
</span></pre>
</ul>
</dd>
<dt>
<a name = "Edge:length"></a>
<strong>Edge:length ()</strong>
</dt>
<dd>
Returns the length.
<h3>Returns:</h3>
<ol>
the length of self
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> e = Edge(Point(), Point(<span class="number">10</span>,<span class="number">0</span>))
<span class="global">print</span>(e:length()) <span class="comment">--&gt; 10
</span></pre>
</ul>
</dd>
<dt>
<a name = "Edge:getMidPoint"></a>
<strong>Edge:getMidPoint ()</strong>
</dt>
<dd>
Returns the midpoint coordinates.
<h3>Returns:</h3>
<ol>
<li>
the x-coordinate of self midpoint</li>
<li>
the y-coordinate of self midpoint</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> e = Edge(Point(), Point(<span class="number">10</span>,<span class="number">0</span>))
<span class="global">print</span>(e:getMidPoint()) <span class="comment">--&gt; 5, 0
</span></pre>
</ul>
</dd>
</dl>
<h2><a name="Class_Point"></a>Class Point </h2>
<dl class="function">
<dt>
<a name = "Point:new"></a>
<strong>Point:new (x, y)</strong>
</dt>
<dd>
Creates a new <a href="../index.html#Class_Point">Point</a>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">x</span>
the x-coordinate
</li>
<li><span class="parameter">y</span>
the y-coordinate
</li>
</ul>
<h3>Returns:</h3>
<ol>
a new <a href="../index.html#Class_Point">Point</a>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> Delaunay = <span class="global">require</span> <span class="string">'Delaunay'</span>
<span class="keyword">local</span> Point = Delaunay.Point
<span class="keyword">local</span> p = Point:new(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> p = Point(<span class="number">1</span>,<span class="number">1</span>) <span class="comment">-- Alias to Point.new
</span> <span class="global">print</span>(p) <span class="comment">-- print the point members x and y
</span></pre>
</ul>
</dd>
<dt>
<a name = "Point:dist2"></a>
<strong>Point:dist2 (p)</strong>
</dt>
<dd>
Returns the square distance to another <a href="../index.html#Class_Point">Point</a> .
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">p</span>
a <a href="../index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
the square distance from self to <code>p</code>.
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2 = Point(), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="global">print</span>(p1:dist2(p2)) <span class="comment">--&gt; 2
</span></pre>
</ul>
</dd>
<dt>
<a name = "Point:dist"></a>
<strong>Point:dist (p)</strong>
</dt>
<dd>
Returns the distance to another <a href="../index.html#Class_Point">Point</a> .
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">p</span>
a <a href="../index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
the distance from self to <code>p</code>.
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2 = Point(), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="global">print</span>(p1:dist2(p2)) <span class="comment">--&gt; 1.4142135623731
</span></pre>
</ul>
</dd>
<dt>
<a name = "Point:isInCircle"></a>
<strong>Point:isInCircle (cx, cy, r)</strong>
</dt>
<dd>
Checks if self lies into the bounds of a circle
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">cx</span>
the x-coordinate of the circle center
</li>
<li><span class="parameter">cy</span>
the y-coordinate of the circle center
</li>
<li><span class="parameter">r</span>
the radius of the circle
</li>
</ul>
<h3>Returns:</h3>
<ol>
<code>true</code> or <code>false</code>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p = Point()
<span class="global">print</span>(p:isInCircle(<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>)) <span class="comment">--&gt; true
</span></pre>
</ul>
</dd>
</dl>
<h2><a name="Class_Triangle"></a>Class Triangle </h2>
<dl class="function">
<dt>
<a name = "Triangle:new"></a>
<strong>Triangle:new (p1, p2, p3)</strong>
</dt>
<dd>
Creates a new <a href="../index.html#Class_Triangle">Triangle</a>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">p1</span>
a <a href="../index.html#Class_Point">Point</a>
</li>
<li><span class="parameter">p2</span>
a <a href="../index.html#Class_Point">Point</a>
</li>
<li><span class="parameter">p3</span>
a <a href="../index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
a new <a href="../index.html#Class_Triangle">Triangle</a>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> Delaunay = <span class="global">require</span> <span class="string">'Delaunay'</span>
<span class="keyword">local</span> Triangle = Delaunay.Triangle
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle:new(p1, p2, p3)
<span class="keyword">local</span> t = Triangle(p1, p2, p3) <span class="comment">-- Alias to Triangle.new
</span> <span class="global">print</span>(t) <span class="comment">-- print the triangle members p1, p2 and p3
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:isCW"></a>
<strong>Triangle:isCW ()</strong>
</dt>
<dd>
Checks if the triangle is defined clockwise (sequence p1-p2-p3)
<h3>Returns:</h3>
<ol>
<code>true</code> or <code>false</code>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">1</span>,<span class="number">1</span>), Point(<span class="number">2</span>,<span class="number">0</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:isCW()) <span class="comment">--&gt; true
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:isCCW"></a>
<strong>Triangle:isCCW ()</strong>
</dt>
<dd>
Checks if the triangle is defined counter-clockwise (sequence p1-p2-p3)
<h3>Returns:</h3>
<ol>
<code>true</code> or <code>false</code>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:isCCW()) <span class="comment">--&gt; true
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getSidesLength"></a>
<strong>Triangle:getSidesLength ()</strong>
</dt>
<dd>
Returns the length of the edges
<h3>Returns:</h3>
<ol>
<li>
the length of the edge p1-p2</li>
<li>
the length of the edge p2-p3</li>
<li>
the length of the edge p3-p1</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getSidesLength()) <span class="comment">--&gt; 2 1.4142135623731 1.4142135623731
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getCenter"></a>
<strong>Triangle:getCenter ()</strong>
</dt>
<dd>
Returns the coordinates of the center
<h3>Returns:</h3>
<ol>
<li>
the x-coordinate of the center</li>
<li>
the y-coordinate of the center</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getCenter()) <span class="comment">--&gt; 1 0.33333333333333
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getCircumCircle"></a>
<strong>Triangle:getCircumCircle ()</strong>
</dt>
<dd>
Returns the coordinates of the circumcircle center and its radius
<h3>Returns:</h3>
<ol>
<li>
the x-coordinate of the circumcircle center</li>
<li>
the y-coordinate of the circumcircle center</li>
<li>
the radius of the circumcircle</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getCircumCircle()) <span class="comment">--&gt; 1 0 1
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getCircumCenter"></a>
<strong>Triangle:getCircumCenter ()</strong>
</dt>
<dd>
Returns the coordinates of the circumcircle center
<h3>Returns:</h3>
<ol>
<li>
the x-coordinate of the circumcircle center</li>
<li>
the y-coordinate of the circumcircle center</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getCircumCenter()) <span class="comment">--&gt; 1 0
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getCircumRadius"></a>
<strong>Triangle:getCircumRadius ()</strong>
</dt>
<dd>
Returns the radius of the circumcircle
<h3>Returns:</h3>
<ol>
the radius of the circumcircle
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getCircumRadius()) <span class="comment">--&gt; 1
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:getArea"></a>
<strong>Triangle:getArea ()</strong>
</dt>
<dd>
Returns the area
<h3>Returns:</h3>
<ol>
the area
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:getArea()) <span class="comment">--&gt; 1
</span></pre>
</ul>
</dd>
<dt>
<a name = "Triangle:inCircumCircle"></a>
<strong>Triangle:inCircumCircle (p)</strong>
</dt>
<dd>
Checks if a given point lies into the triangle circumcircle
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">p</span>
a <a href="../index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<code>true</code> or <code>false</code>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> p1, p2, p3 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>)
<span class="keyword">local</span> t = Triangle(p1, p2, p3)
<span class="global">print</span>(t:inCircumCircle(Point(<span class="number">1</span>,-<span class="number">1</span>))) <span class="comment">--&gt; true
</span></pre>
</ul>
</dd>
</dl>
<h2><a name="Delaunay_module"></a>Delaunay module </h2>
<dl class="function">
<dt>
<a name = "Delaunay"></a>
<strong>Delaunay</strong>
</dt>
<dd>
Delaunay module
<h3>Fields:</h3>
<ul>
<li><span class="parameter">Point</span>
reference to the <a href="../index.html#Class_Point">Point</a> class
</li>
<li><span class="parameter">Edge</span>
reference to the <a href="../index.html#Class_Edge">Edge</a> class
</li>
<li><span class="parameter">Triangle</span>
reference to the <a href="../index.html#Class_Triangle">Triangle</a> class
</li>
<li><span class="parameter">_VERSION</span>
the version of the current module
</li>
</ul>
</dd>
<dt>
<a name = "Delaunay.triangulate"></a>
<strong>Delaunay.triangulate (...)</strong>
</dt>
<dd>
Triangulates a set of given vertices
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">...</span>
a <code>vargarg</code> list of objects of type <a href="../index.html#Class_Point">Point</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
a set of objects of type <a href="../index.html#Class_Triangle">Triangle</a>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">
<span class="keyword">local</span> Delaunay = <span class="global">require</span> <span class="string">'Delaunay'</span>
<span class="keyword">local</span> Point = Delaunay.Point
<span class="keyword">local</span> p1, p2, p3, p4 = Point(), Point(<span class="number">2</span>,<span class="number">0</span>), Point(<span class="number">1</span>,<span class="number">1</span>), Point(<span class="number">1</span>,-<span class="number">1</span>)
<span class="keyword">local</span> triangles = Delaunay.triangulate(p1, p2, p3, p4)
<span class="keyword">for</span> i = <span class="number">1</span>, #triangles <span class="keyword">do</span>
<span class="global">print</span>(triangles[i])
<span class="keyword">end</span></pre>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.0</a></i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@ -0,0 +1,4 @@
#Version history#
###0.1 (12/26/2013)
* Initial release

448
files/lua/delaunay.lua Normal file
View File

@ -0,0 +1,448 @@
#!/usr/bin/env lua
---------------
-- ## Delaunay, Lua module for convex polygon triangulation
-- @author Roland Yonaba
-- @copyright 2013
-- @license MIT
-- @script delaunay
-- ================
-- Private helpers
-- ================
local setmetatable = setmetatable
local tostring = tostring
local assert = assert
local unpack = unpack
local remove = table.remove
local sqrt = math.sqrt
local max = math.max
-- Internal class constructor
local class = function(...)
local klass = {}
klass.__index = klass
klass.__call = function(_,...) return klass:new(...) end
function klass:new(...)
local instance = setmetatable({}, klass)
klass.__init(instance, ...)
return instance
end
return setmetatable(klass,{__call = klass.__call})
end
-- Triangle semi-perimeter by Heron's formula
local function quatCross(a, b, c)
local p = (a + b + c) * (a + b - c) * (a - b + c) * (-a + b + c)
return sqrt(p)
end
-- Cross product (p1-p2, p2-p3)
local function crossProduct(p1, p2, p3)
local x1, x2 = p2.x - p1.x, p3.x - p2.x
local y1, y2 = p2.y - p1.y, p3.y - p2.y
return x1 * y2 - y1 * x2
end
-- Checks if angle (p1-p2-p3) is flat
local function isFlatAngle(p1, p2, p3)
return (crossProduct(p1, p2, p3) == 0)
end
-- ================
-- Module classes
-- ================
--- `Edge` class
-- @type Edge
local Edge = class()
Edge.__eq = function(a, b) return (a.p1 == b.p1 and a.p2 == b.p2) end
Edge.__tostring = function(e)
return (('Edge :\n %s\n %s'):format(tostring(e.p1), tostring(e.p2)))
end
--- Creates a new `Edge`
-- @name Edge:new
-- @param p1 a `Point`
-- @param p2 a `Point`
-- @return a new `Edge`
-- @usage
-- local Delaunay = require 'Delaunay'
-- local Edge = Delaunay.Edge
-- local Point = Delaunay.Point
-- local e = Edge:new(Point(1,1), Point(2,5))
-- local e = Edge(Point(1,1), Point(2,5)) -- Alias to Edge.new
-- print(e) -- print the edge members p1 and p2
--
function Edge:__init(p1, p2)
self.p1, self.p2 = p1, p2
end
--- Test if `otherEdge` is similar to self. It does not take into account the direction.
-- @param otherEdge an `Edge`
-- @return `true` or `false`
-- @usage
-- local e1 = Edge(Point(1,1), Point(2,5))
-- local e2 = Edge(Point(2,5), Point(1,1))
-- print(e1:same(e2)) --> true
-- print(e1 == e2)) --> false, == operator considers the direction
--
function Edge:same(otherEdge)
return ((self.p1 == otherEdge.p1) and (self.p2 == otherEdge.p2))
or ((self.p1 == otherEdge.p2) and (self.p2 == otherEdge.p1))
end
--- Returns the length.
-- @return the length of self
-- @usage
-- local e = Edge(Point(), Point(10,0))
-- print(e:length()) --> 10
--
function Edge:length()
return self.p1:dist(self.p2)
end
--- Returns the midpoint coordinates.
-- @return the x-coordinate of self midpoint
-- @return the y-coordinate of self midpoint
-- @usage
-- local e = Edge(Point(), Point(10,0))
-- print(e:getMidPoint()) --> 5, 0
--
function Edge:getMidPoint()
local x = self.p1.x + (self.p2.x - self.p1.x) / 2
local y = self.p1.x + (self.p2.y - self.p1.y) / 2
return x, y
end
--- Point class
-- @type Point
local Point = class()
Point.__eq = function(a,b) return (a.x == b.x and a.y == b.y) end
Point.__tostring = function(p)
return ('Point (%s) x: %.2f y: %.2f'):format(p.id, p.x, p.y)
end
--- Creates a new `Point`
-- @name Point:new
-- @param x the x-coordinate
-- @param y the y-coordinate
-- @return a new `Point`
-- @usage
-- local Delaunay = require 'Delaunay'
-- local Point = Delaunay.Point
-- local p = Point:new(1,1)
-- local p = Point(1,1) -- Alias to Point.new
-- print(p) -- print the point members x and y
--
function Point:__init(x, y)
self.x, self.y, self.id = x or 0, y or 0, '?'
end
--- Returns the square distance to another `Point`.
-- @param p a `Point`
-- @return the square distance from self to `p`.
-- @usage
-- local p1, p2 = Point(), Point(1,1)
-- print(p1:dist2(p2)) --> 2
--
function Point:dist2(p)
local dx, dy = (self.x - p.x), (self.y - p.y)
return dx * dx + dy * dy
end
--- Returns the distance to another `Point`.
-- @param p a `Point`
-- @return the distance from self to `p`.
-- @usage
-- local p1, p2 = Point(), Point(1,1)
-- print(p1:dist2(p2)) --> 1.4142135623731
--
function Point:dist(p)
return sqrt(self:dist2(p))
end
--- Checks if self lies into the bounds of a circle
-- @param cx the x-coordinate of the circle center
-- @param cy the y-coordinate of the circle center
-- @param r the radius of the circle
-- @return `true` or `false`
-- @usage
-- local p = Point()
-- print(p:isInCircle(0,0,1)) --> true
--
function Point:isInCircle(cx, cy, r)
local dx = (cx - self.x)
local dy = (cy - self.y)
return ((dx * dx + dy * dy) <= (r * r))
end
--- `Triangle` class
-- @type Triangle
local Triangle = class()
Triangle.__tostring = function(t)
return (('Triangle: \n %s\n %s\n %s')
:format(tostring(t.p1), tostring(t.p2), tostring(t.p3)))
end
--- Creates a new `Triangle`
-- @name Triangle:new
-- @param p1 a `Point`
-- @param p2 a `Point`
-- @param p3 a `Point`
-- @return a new `Triangle`
-- @usage
-- local Delaunay = require 'Delaunay'
-- local Triangle = Delaunay.Triangle
-- local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
-- local t = Triangle:new(p1, p2, p3)
-- local t = Triangle(p1, p2, p3) -- Alias to Triangle.new
-- print(t) -- print the triangle members p1, p2 and p3
--
function Triangle:__init(p1, p2, p3)
assert(not isFlatAngle(p1, p2, p3), ("angle (p1, p2, p3) is flat:\n %s\n %s\n %s")
:format(tostring(p1), tostring(p2), tostring(p3)))
self.p1, self.p2, self.p3 = p1, p2, p3
self.e1, self.e2, self.e3 = Edge(p1, p2), Edge(p2, p3), Edge(p3, p1)
end
--- Checks if the triangle is defined clockwise (sequence p1-p2-p3)
-- @return `true` or `false`
-- @usage
-- local p1, p2, p3 = Point(), Point(1,1), Point(2,0)
-- local t = Triangle(p1, p2, p3)
-- print(t:isCW()) --> true
--
function Triangle:isCW()
return (crossProduct(self.p1, self.p2, self.p3) < 0)
end
--- Checks if the triangle is defined counter-clockwise (sequence p1-p2-p3)
-- @return `true` or `false`
-- @usage
-- local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
-- local t = Triangle(p1, p2, p3)
-- print(t:isCCW()) --> true
--
function Triangle:isCCW()
return (crossProduct(self.p1, self.p2, self.p3) > 0)
end
--- Returns the length of the edges
-- @return the length of the edge p1-p2
-- @return the length of the edge p2-p3
-- @return the length of the edge p3-p1
-- @usage
-- local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
-- local t = Triangle(p1, p2, p3)
-- print(t:getSidesLength()) --> 2 1.4142135623731 1.4142135623731
--
function Triangle:getSidesLength()
return self.e1:length(), self.e2:length(), self.e3:length()
end
--- Returns the coordinates of the center
-- @return the x-coordinate of the center
-- @return the y-coordinate of the center
-- @usage
-- local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
-- local t = Triangle(p1, p2, p3)
-- print(t:getCenter()) --> 1 0.33333333333333
--
function Triangle:getCenter()
local x = (self.p1.x + self.p2.x + self.p3.x) / 3
local y = (self.p1.y + self.p2.y + self.p3.y) / 3
return x, y
end
--- Returns the coordinates of the circumcircle center and its radius
-- @return the x-coordinate of the circumcircle center
-- @return the y-coordinate of the circumcircle center
-- @return the radius of the circumcircle
-- @usage
-- local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
-- local t = Triangle(p1, p2, p3)
-- print(t:getCircumCircle()) --> 1 0 1
--
function Triangle:getCircumCircle()
local x, y = self:getCircumCenter()
local r = self:getCircumRadius()
return x, y, r
end
--- Returns the coordinates of the circumcircle center
-- @return the x-coordinate of the circumcircle center
-- @return the y-coordinate of the circumcircle center
-- @usage
-- local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
-- local t = Triangle(p1, p2, p3)
-- print(t:getCircumCenter()) --> 1 0
--
function Triangle:getCircumCenter()
local p1, p2, p3 = self.p1, self.p2, self.p3
local D = ( p1.x * (p2.y - p3.y) +
p2.x * (p3.y - p1.y) +
p3.x * (p1.y - p2.y)) * 2
local x = (( p1.x * p1.x + p1.y * p1.y) * (p2.y - p3.y) +
( p2.x * p2.x + p2.y * p2.y) * (p3.y - p1.y) +
( p3.x * p3.x + p3.y * p3.y) * (p1.y - p2.y))
local y = (( p1.x * p1.x + p1.y * p1.y) * (p3.x - p2.x) +
( p2.x * p2.x + p2.y * p2.y) * (p1.x - p3.x) +
( p3.x * p3.x + p3.y * p3.y) * (p2.x - p1.x))
return (x / D), (y / D)
end
--- Returns the radius of the circumcircle
-- @return the radius of the circumcircle
-- @usage
-- local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
-- local t = Triangle(p1, p2, p3)
-- print(t:getCircumRadius()) --> 1
--
function Triangle:getCircumRadius()
local a, b, c = self:getSidesLength()
return ((a * b * c) / quatCross(a, b, c))
end
--- Returns the area
-- @return the area
-- @usage
-- local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
-- local t = Triangle(p1, p2, p3)
-- print(t:getArea()) --> 1
--
function Triangle:getArea()
local a, b, c = self:getSidesLength()
return (quatCross(a, b, c) / 4)
end
--- Checks if a given point lies into the triangle circumcircle
-- @param p a `Point`
-- @return `true` or `false`
-- @usage
-- local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
-- local t = Triangle(p1, p2, p3)
-- print(t:inCircumCircle(Point(1,-1))) --> true
--
function Triangle:inCircumCircle(p)
return p:isInCircle(self:getCircumCircle())
end
--- Delaunay module
-- @section public
--- Delaunay module
-- @table Delaunay
-- @field Point reference to the `Point` class
-- @field Edge reference to the `Edge` class
-- @field Triangle reference to the `Triangle` class
-- @field _VERSION the version of the current module
local Delaunay = {
Point = Point,
Edge = Edge,
Triangle = Triangle,
_VERSION = "0.1"
}
--- Triangulates a set of given vertices
-- @param ... a `vargarg` list of objects of type `Point`
-- @return a set of objects of type `Triangle`
-- @usage
-- local Delaunay = require 'Delaunay'
-- local Point = Delaunay.Point
-- local p1, p2, p3, p4 = Point(), Point(2,0), Point(1,1), Point(1,-1)
-- local triangles = Delaunay.triangulate(p1, p2, p3, p4)
-- for i = 1, #triangles do
-- print(triangles[i])
-- end
--
function Delaunay.triangulate(...)
local vertices = {...}
local nvertices = #vertices
assert(nvertices > 2, "Cannot triangulate, needs more than 3 vertices")
if nvertices == 3 then
return {Triangle(unpack(vertices))}
end
local trmax = nvertices * 4
local minX, minY = vertices[1].x, vertices[1].y
local maxX, maxY = minX, minY
for i = 1, #vertices do
local vertex = vertices[i]
vertex.id = i
if vertex.x < minX then minX = vertex.x end
if vertex.y < minY then minY = vertex.y end
if vertex.x > maxX then maxX = vertex.x end
if vertex.y > maxY then maxY = vertex.y end
end
local dx, dy = maxX - minX, maxY - minY
local deltaMax = max(dx, dy)
local midx, midy = (minX + maxX) * 0.5, (minY + maxY) * 0.5
local p1 = Point(midx - 2 * deltaMax, midy - deltaMax)
local p2 = Point(midx, midy + 2 * deltaMax)
local p3 = Point(midx + 2 * deltaMax, midy - deltaMax)
p1.id, p2.id, p3.id = nvertices + 1, nvertices + 2, nvertices + 3
vertices[p1.id] = p1
vertices[p2.id] = p2
vertices[p3.id] = p3
local triangles = {}
triangles[#triangles + 1] = Triangle(vertices[nvertices + 1],
vertices[nvertices + 2],
vertices[nvertices + 3]
)
for i = 1, nvertices do
local edges = {}
local ntriangles = #triangles
for j = #triangles, 1, -1 do
local curTriangle = triangles[j]
if curTriangle:inCircumCircle(vertices[i]) then
edges[#edges + 1] = curTriangle.e1
edges[#edges + 1] = curTriangle.e2
edges[#edges + 1] = curTriangle.e3
remove(triangles, j)
end
end
for j = #edges - 1, 1, -1 do
for k = #edges, j + 1, -1 do
if edges[j] and edges[k] and edges[j]:same(edges[k]) then
remove(edges, j)
remove(edges, k-1)
end
end
end
for j = 1, #edges do
local n = #triangles
assert(n <= trmax, "Generated more than needed triangles")
triangles[n + 1] = Triangle(edges[j].p1, edges[j].p2, vertices[i])
end
end
for i = #triangles, 1, -1 do
local triangle = triangles[i]
if (triangle.p1.id > nvertices or
triangle.p2.id > nvertices or
triangle.p3.id > nvertices) then
remove(triangles, i)
end
end
for _ = 1,3 do remove(vertices) end
return triangles
end
return Delaunay

View File

@ -0,0 +1,38 @@
local Delaunay = require ('Delaunay')
local Point = Delaunay.Point
math.randomseed(os.time())
local function newPoint()
local x, y = math.random(), math.random()
return Point(x * 1000, y * 1000)
end
local MAX_POINTS = arg[1] or 500
local N_TESTS = arg[2] or 10
local function genPoints(n)
local points = {}
for i = 1, n do
points[i] = newPoint()
end
return points
end
local function time(f, p)
local start_time = os.clock()
local result = f(unpack(p))
local duration = (os.clock() - start_time) * 1000
assert(result~=nil, 'Unexpected output, returned nil')
return duration
end
local function main()
for i = 1, N_TESTS do
local p = genPoints(MAX_POINTS)
local duration = time(Delaunay.triangulate, p)
print(('Test %02d: triangulating %04d points in %.2f ms'):format(i, MAX_POINTS, duration))
end
end
main()