diff --git a/files/docs/delaunay/LICENSE b/files/docs/delaunay/LICENSE new file mode 100644 index 0000000..4f69f6b --- /dev/null +++ b/files/docs/delaunay/LICENSE @@ -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. diff --git a/files/docs/delaunay/README.md b/files/docs/delaunay/README.md new file mode 100644 index 0000000..7af5cdc --- /dev/null +++ b/files/docs/delaunay/README.md @@ -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.
+ +##Usage + +The module provides 3 classes:
+* `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).
+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") \ No newline at end of file diff --git a/files/docs/delaunay/index.html b/files/docs/delaunay/index.html new file mode 100644 index 0000000..c171009 --- /dev/null +++ b/files/docs/delaunay/index.html @@ -0,0 +1,801 @@ + + + + + Delaunay module documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Script delaunay

+ +

+

Delaunay, Lua module for convex polygon triangulation

+

+

+ +

+

Info:

+
    +
  • Copyright: 2013
  • +
  • License: MIT
  • +
  • Author: Roland Yonaba
  • +
+ + +

Class Edge

+ + + + + + + + + + + + + + + + + +
Edge:new (p1, p2)Creates a new Edge
Edge:same (otherEdge)Test if otherEdge is similar to self.
Edge:length ()Returns the length.
Edge:getMidPoint ()Returns the midpoint coordinates.
+

Class Point

+ + + + + + + + + + + + + + + + + +
Point:new (x, y)Creates a new Point
Point:dist2 (p)Returns the square distance to another Point .
Point:dist (p)Returns the distance to another Point .
Point:isInCircle (cx, cy, r)Checks if self lies into the bounds of a circle
+

Class Triangle

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Triangle:new (p1, p2, p3)Creates a new Triangle
Triangle:isCW ()Checks if the triangle is defined clockwise (sequence p1-p2-p3)
Triangle:isCCW ()Checks if the triangle is defined counter-clockwise (sequence p1-p2-p3)
Triangle:getSidesLength ()Returns the length of the edges
Triangle:getCenter ()Returns the coordinates of the center
Triangle:getCircumCircle ()Returns the coordinates of the circumcircle center and its radius
Triangle:getCircumCenter ()Returns the coordinates of the circumcircle center
Triangle:getCircumRadius ()Returns the radius of the circumcircle
Triangle:getArea ()Returns the area
Triangle:inCircumCircle (p)Checks if a given point lies into the triangle circumcircle
+

Delaunay module

+ + + + + + + + + +
DelaunayDelaunay module
Delaunay.triangulate (...)Triangulates a set of given vertices
+ +
+
+ + +

Class Edge

+ +
+
+ + Edge:new (p1, p2) +
+
+ Creates a new Edge + +

Parameters:

+ + +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Edge:same (otherEdge) +
+
+ Test if otherEdge is similar to self. It does not take into account the direction. + +

Parameters:

+
    +
  • otherEdge + an Edge +
  • +
+ +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Edge:length () +
+
+ Returns the length. + + +

Returns:

+
    + + the length of self +
+ + + +

Usage:

+
    +
    + local e = Edge(Point(), Point(10,0))
    + print(e:length()) --> 10
    +
    +
+ +
+
+ + Edge:getMidPoint () +
+
+ Returns the midpoint coordinates. + + +

Returns:

+
    +
  1. + the x-coordinate of self midpoint
  2. +
  3. + the y-coordinate of self midpoint
  4. +
+ + + +

Usage:

+
    +
    + local e = Edge(Point(), Point(10,0))
    + print(e:getMidPoint()) --> 5, 0
    +
    +
+ +
+
+

Class Point

+ +
+
+ + Point:new (x, y) +
+
+ Creates a new Point + +

Parameters:

+
    +
  • x + the x-coordinate +
  • +
  • y + the y-coordinate +
  • +
+ +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Point:dist2 (p) +
+
+ Returns the square distance to another Point . + +

Parameters:

+ + +

Returns:

+
    + + the square distance from self to p. +
+ + + +

Usage:

+
    +
    + local p1, p2 = Point(), Point(1,1)
    + print(p1:dist2(p2)) --> 2
    +
    +
+ +
+
+ + Point:dist (p) +
+
+ Returns the distance to another Point . + +

Parameters:

+ + +

Returns:

+
    + + the distance from self to p. +
+ + + +

Usage:

+
    +
    + local p1, p2 = Point(), Point(1,1)
    + print(p1:dist2(p2)) --> 1.4142135623731
    +
    +
+ +
+
+ + Point:isInCircle (cx, cy, r) +
+
+ Checks if self lies into the bounds of a circle + +

Parameters:

+
    +
  • cx + the x-coordinate of the circle center +
  • +
  • cy + the y-coordinate of the circle center +
  • +
  • r + the radius of the circle +
  • +
+ +

Returns:

+
    + + true or false +
+ + + +

Usage:

+
    +
    + local p = Point()
    + print(p:isInCircle(0,0,1)) --> true
    +
    +
+ +
+
+

Class Triangle

+ +
+
+ + Triangle:new (p1, p2, p3) +
+
+ Creates a new Triangle + +

Parameters:

+ + +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Triangle:isCW () +
+
+ Checks if the triangle is defined clockwise (sequence p1-p2-p3) + + +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Triangle:isCCW () +
+
+ Checks if the triangle is defined counter-clockwise (sequence p1-p2-p3) + + +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Triangle:getSidesLength () +
+
+ Returns the length of the edges + + +

Returns:

+
    +
  1. + the length of the edge p1-p2
  2. +
  3. + the length of the edge p2-p3
  4. +
  5. + the length of the edge p3-p1
  6. +
+ + + +

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
    +
    +
+ +
+
+ + Triangle:getCenter () +
+
+ Returns the coordinates of the center + + +

Returns:

+
    +
  1. + the x-coordinate of the center
  2. +
  3. + the y-coordinate of the center
  4. +
+ + + +

Usage:

+
    +
    + local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
    + local t = Triangle(p1, p2, p3)
    + print(t:getCenter()) --> 1 0.33333333333333
    +
    +
+ +
+
+ + Triangle:getCircumCircle () +
+
+ Returns the coordinates of the circumcircle center and its radius + + +

Returns:

+
    +
  1. + the x-coordinate of the circumcircle center
  2. +
  3. + the y-coordinate of the circumcircle center
  4. +
  5. + the radius of the circumcircle
  6. +
+ + + +

Usage:

+
    +
    + local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
    + local t = Triangle(p1, p2, p3)
    + print(t:getCircumCircle()) --> 1	0	1
    +
    +
+ +
+
+ + Triangle:getCircumCenter () +
+
+ Returns the coordinates of the circumcircle center + + +

Returns:

+
    +
  1. + the x-coordinate of the circumcircle center
  2. +
  3. + the y-coordinate of the circumcircle center
  4. +
+ + + +

Usage:

+
    +
    + local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
    + local t = Triangle(p1, p2, p3)
    + print(t:getCircumCenter()) --> 1	0
    +
    +
+ +
+
+ + Triangle:getCircumRadius () +
+
+ Returns the radius of the circumcircle + + +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Triangle:getArea () +
+
+ Returns the area + + +

Returns:

+
    + + the area +
+ + + +

Usage:

+
    +
    + local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
    + local t = Triangle(p1, p2, p3)
    + print(t:getArea()) --> 1
    +
    +
+ +
+
+ + Triangle:inCircumCircle (p) +
+
+ Checks if a given point lies into the triangle circumcircle + +

Parameters:

+ + +

Returns:

+
    + + 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
    +
    +
+ +
+
+

Delaunay module

+ +
+
+ + Delaunay +
+
+ Delaunay module + +

Fields:

+
    +
  • Point + reference to the Point class +
  • +
  • Edge + reference to the Edge class +
  • +
  • Triangle + reference to the Triangle class +
  • +
  • _VERSION + the version of the current module +
  • +
+ + + + + +
+
+ + Delaunay.triangulate (...) +
+
+ Triangulates a set of given vertices + +

Parameters:

+
    +
  • ... + a vargarg list of objects of type Point +
  • +
+ +

Returns:

+
    + + 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
    +
+ +
+
+ + +
+
+
+generated by LDoc 1.4.0 +
+
+ + diff --git a/files/docs/delaunay/scripts/delaunay.html b/files/docs/delaunay/scripts/delaunay.html new file mode 100644 index 0000000..c2ba8f4 --- /dev/null +++ b/files/docs/delaunay/scripts/delaunay.html @@ -0,0 +1,801 @@ + + + + + Delaunay module documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Script delaunay

+ +

+

Delaunay, Lua module for convex polygon triangulation

+

+

+ +

+

Info:

+
    +
  • Copyright: 2013
  • +
  • License: MIT
  • +
  • Author: Roland Yonaba
  • +
+ + +

Class Edge

+ + + + + + + + + + + + + + + + + +
Edge:new (p1, p2)Creates a new Edge
Edge:same (otherEdge)Test if otherEdge is similar to self.
Edge:length ()Returns the length.
Edge:getMidPoint ()Returns the midpoint coordinates.
+

Class Point

+ + + + + + + + + + + + + + + + + +
Point:new (x, y)Creates a new Point
Point:dist2 (p)Returns the square distance to another Point .
Point:dist (p)Returns the distance to another Point .
Point:isInCircle (cx, cy, r)Checks if self lies into the bounds of a circle
+

Class Triangle

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Triangle:new (p1, p2, p3)Creates a new Triangle
Triangle:isCW ()Checks if the triangle is defined clockwise (sequence p1-p2-p3)
Triangle:isCCW ()Checks if the triangle is defined counter-clockwise (sequence p1-p2-p3)
Triangle:getSidesLength ()Returns the length of the edges
Triangle:getCenter ()Returns the coordinates of the center
Triangle:getCircumCircle ()Returns the coordinates of the circumcircle center and its radius
Triangle:getCircumCenter ()Returns the coordinates of the circumcircle center
Triangle:getCircumRadius ()Returns the radius of the circumcircle
Triangle:getArea ()Returns the area
Triangle:inCircumCircle (p)Checks if a given point lies into the triangle circumcircle
+

Delaunay module

+ + + + + + + + + +
DelaunayDelaunay module
Delaunay.triangulate (...)Triangulates a set of given vertices
+ +
+
+ + +

Class Edge

+ +
+
+ + Edge:new (p1, p2) +
+
+ Creates a new Edge + +

Parameters:

+ + +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Edge:same (otherEdge) +
+
+ Test if otherEdge is similar to self. It does not take into account the direction. + +

Parameters:

+
    +
  • otherEdge + an Edge +
  • +
+ +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Edge:length () +
+
+ Returns the length. + + +

Returns:

+
    + + the length of self +
+ + + +

Usage:

+
    +
    + local e = Edge(Point(), Point(10,0))
    + print(e:length()) --> 10
    +
    +
+ +
+
+ + Edge:getMidPoint () +
+
+ Returns the midpoint coordinates. + + +

Returns:

+
    +
  1. + the x-coordinate of self midpoint
  2. +
  3. + the y-coordinate of self midpoint
  4. +
+ + + +

Usage:

+
    +
    + local e = Edge(Point(), Point(10,0))
    + print(e:getMidPoint()) --> 5, 0
    +
    +
+ +
+
+

Class Point

+ +
+
+ + Point:new (x, y) +
+
+ Creates a new Point + +

Parameters:

+
    +
  • x + the x-coordinate +
  • +
  • y + the y-coordinate +
  • +
+ +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Point:dist2 (p) +
+
+ Returns the square distance to another Point . + +

Parameters:

+ + +

Returns:

+
    + + the square distance from self to p. +
+ + + +

Usage:

+
    +
    + local p1, p2 = Point(), Point(1,1)
    + print(p1:dist2(p2)) --> 2
    +
    +
+ +
+
+ + Point:dist (p) +
+
+ Returns the distance to another Point . + +

Parameters:

+ + +

Returns:

+
    + + the distance from self to p. +
+ + + +

Usage:

+
    +
    + local p1, p2 = Point(), Point(1,1)
    + print(p1:dist2(p2)) --> 1.4142135623731
    +
    +
+ +
+
+ + Point:isInCircle (cx, cy, r) +
+
+ Checks if self lies into the bounds of a circle + +

Parameters:

+
    +
  • cx + the x-coordinate of the circle center +
  • +
  • cy + the y-coordinate of the circle center +
  • +
  • r + the radius of the circle +
  • +
+ +

Returns:

+
    + + true or false +
+ + + +

Usage:

+
    +
    + local p = Point()
    + print(p:isInCircle(0,0,1)) --> true
    +
    +
+ +
+
+

Class Triangle

+ +
+
+ + Triangle:new (p1, p2, p3) +
+
+ Creates a new Triangle + +

Parameters:

+ + +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Triangle:isCW () +
+
+ Checks if the triangle is defined clockwise (sequence p1-p2-p3) + + +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Triangle:isCCW () +
+
+ Checks if the triangle is defined counter-clockwise (sequence p1-p2-p3) + + +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Triangle:getSidesLength () +
+
+ Returns the length of the edges + + +

Returns:

+
    +
  1. + the length of the edge p1-p2
  2. +
  3. + the length of the edge p2-p3
  4. +
  5. + the length of the edge p3-p1
  6. +
+ + + +

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
    +
    +
+ +
+
+ + Triangle:getCenter () +
+
+ Returns the coordinates of the center + + +

Returns:

+
    +
  1. + the x-coordinate of the center
  2. +
  3. + the y-coordinate of the center
  4. +
+ + + +

Usage:

+
    +
    + local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
    + local t = Triangle(p1, p2, p3)
    + print(t:getCenter()) --> 1 0.33333333333333
    +
    +
+ +
+
+ + Triangle:getCircumCircle () +
+
+ Returns the coordinates of the circumcircle center and its radius + + +

Returns:

+
    +
  1. + the x-coordinate of the circumcircle center
  2. +
  3. + the y-coordinate of the circumcircle center
  4. +
  5. + the radius of the circumcircle
  6. +
+ + + +

Usage:

+
    +
    + local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
    + local t = Triangle(p1, p2, p3)
    + print(t:getCircumCircle()) --> 1	0	1
    +
    +
+ +
+
+ + Triangle:getCircumCenter () +
+
+ Returns the coordinates of the circumcircle center + + +

Returns:

+
    +
  1. + the x-coordinate of the circumcircle center
  2. +
  3. + the y-coordinate of the circumcircle center
  4. +
+ + + +

Usage:

+
    +
    + local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
    + local t = Triangle(p1, p2, p3)
    + print(t:getCircumCenter()) --> 1	0
    +
    +
+ +
+
+ + Triangle:getCircumRadius () +
+
+ Returns the radius of the circumcircle + + +

Returns:

+
    + + 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
    +
    +
+ +
+
+ + Triangle:getArea () +
+
+ Returns the area + + +

Returns:

+
    + + the area +
+ + + +

Usage:

+
    +
    + local p1, p2, p3 = Point(), Point(2,0), Point(1,1)
    + local t = Triangle(p1, p2, p3)
    + print(t:getArea()) --> 1
    +
    +
+ +
+
+ + Triangle:inCircumCircle (p) +
+
+ Checks if a given point lies into the triangle circumcircle + +

Parameters:

+ + +

Returns:

+
    + + 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
    +
    +
+ +
+
+

Delaunay module

+ +
+
+ + Delaunay +
+
+ Delaunay module + +

Fields:

+
    +
  • Point + reference to the Point class +
  • +
  • Edge + reference to the Edge class +
  • +
  • Triangle + reference to the Triangle class +
  • +
  • _VERSION + the version of the current module +
  • +
+ + + + + +
+
+ + Delaunay.triangulate (...) +
+
+ Triangulates a set of given vertices + +

Parameters:

+
    +
  • ... + a vargarg list of objects of type Point +
  • +
+ +

Returns:

+
    + + 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
    +
+ +
+
+ + +
+
+
+generated by LDoc 1.4.0 +
+
+ + diff --git a/files/docs/delaunay/version_history.md b/files/docs/delaunay/version_history.md new file mode 100644 index 0000000..26830ae --- /dev/null +++ b/files/docs/delaunay/version_history.md @@ -0,0 +1,4 @@ +#Version history# + +###0.1 (12/26/2013) +* Initial release \ No newline at end of file diff --git a/files/lua/delaunay.lua b/files/lua/delaunay.lua new file mode 100644 index 0000000..b5eae5b --- /dev/null +++ b/files/lua/delaunay.lua @@ -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 \ No newline at end of file diff --git a/files/utils/delaunay/bench.lua b/files/utils/delaunay/bench.lua new file mode 100644 index 0000000..af2cd84 --- /dev/null +++ b/files/utils/delaunay/bench.lua @@ -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() \ No newline at end of file