diff --git a/Changes.txt b/Changes.txt
index 0b27b9d..78897e1 100644
--- a/Changes.txt
+++ b/Changes.txt
@@ -1,4 +1,39 @@
-MLib changelog- accurate since 0.3.0.0 (previously known as 3.0.0), short description from before then.
+MLib changelog- accurate since 3.0.0 (now known as 0.3.0.0), short description from before then.
+
+1.0.0.2
+====
+Added:
+----
+
+Removed:
+----
+- Ability to use a direction for Math.GetAngle's 5th argument instead of having a third point. See Fixed for more.
+
+Changed:
+----
+- Changed README.md for clarity and consistency.
+- Updated spec.lua
+- See Fixed for more.
+
+Fixed:
+----
+- Circle.IsSegmentSecant now properly accounts for chords actually being chords, and not secants.
+- Circle.CircleIntersects now can return 'Colinear' or 'Equal' if the circles have same x and y but different radii (Colinear) or are exactly the same (Equal).
+- Statistics.GetMode now returns a table with the modes, and the second argument as the number of times they appear.
+- Math.GetRoot now returns the negative number as a second argument.
+- Math.GetPercentOfChange now works for 0 to 0 (previously false).
+- Math.GetAngle now takes only three points and no direction option.
+- Typos in Shape.CheckCollisions and Shape.Remove.
+- Fixed nil problems in Shape.CheckCollisions.
+- Improved readablility and DRYness of Shape.CheckCollisions.
+- Bugs in Shape.Remove and Shape.CheckCollisions regarding passing tables as arguments.
+
+TODO:
+- Add:
+ - Frequency
+ - Binomial Probability
+ - Standard Deviation
+ - Conditional Probability
1.0.0.1
====
diff --git a/README.md b/README.md
index 62a3d5a..b54dd24 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ git clone git://github.com/davisdude/mlib.git
````
###Download
-The __latest release__ can be found here, and previous releases here.
+The __latest release__ can be found here, and previous releases here.
##Usage of MLib
Download the file called `mlib.lua` and put it somewhere in the file for the process you want it in. Use the *require* function to import the module into the library.
@@ -123,7 +123,7 @@ Deals with linear aspects, such as slope. Also handles line segments.
- The distance between the two points.
- Example:
- Gets the length from ( 1, 1 ) to ( 2, 1 ), which is 1.
- - `length = MLib.Line.GetLength( 1, 1, 2, 1 )`
+ - `Length = MLib.Line.GetLength( 1, 1, 2, 1 )`
#####MLib.Line.GetMidpoint
- Gets the midpoint of a two points.
@@ -194,7 +194,7 @@ Deals with linear aspects, such as slope. Also handles line segments.
- Returns:
- The perpendicular slope and the midpoint of the line.
- Example:
- - Gets the perpendicular biisector of ( 1, 1 ) and ( 3, 3 ), which will be -1, 2, 2.
+ - Gets the perpendicular biisector of ( 1, 1 ) and ( 3, 3 ), which will be 2, 2, -1.
- `x, y, PerpendicularSlope = MLib.Line.GetPerpendicularBisector( 1, 1, 3, 3 )`
#####MLib.Line.GetIntercept
@@ -227,6 +227,7 @@ Deals with linear aspects, such as slope. Also handles line segments.
- Synopsis:
- `MLib.Line.GetIntersection( Slope, Intercept, x1, y1, x2, y2 )`
- `MLib.Line.GetIntersection( Slope1, Intercept1, Slope2, Intercept2 )`
+ - `MLib.Line.GetIntersection( x1, y1, x2, y2, x3, y3, x4, y4 )`
- Arguments:
- `MLib.Line.GetIntersection( Slope, Intercept, x1, y1, x2, y2 )`
- `Slope`: Number. The slope of the first line.
@@ -240,6 +241,15 @@ Deals with linear aspects, such as slope. Also handles line segments.
- `Intercept1`: Number. The y-intercept of the first line.
- `Slope2`: Number. The slope of the second line.
- `Intercept2`: Number. The y-intercept of the second line.
+ - `MLib.Line.GetIntersection( x1, y1, x2, y2, x3, y3, x4, y4 )`
+ - `x1`: Number. The one x-coordinate of the first line.
+ - `y1`: Number. The one y-coordinate of the first line.
+ - `x2`: Number. The the other x-coordinate of the second line.
+ - `y2`: Number. The the other y-coordinate of the second line.
+ - `x3`: Number. The one x-coordinate of the third line.
+ - `y3`: Number. The one y-coordinate of the third line.
+ - `x4`: Number. The the other x-coordinate of the fourth line.
+ - `y4`: Number. The the other y-coordinate of the fourth line.
- Returns:
- Where the lines intersect.
- __IMPORTANT__: If the lines are parallel, it will return false.
@@ -381,15 +391,15 @@ Handles polygon-related functions.
- `Base`: Number. Length of the base of the triangle.
- `Area`: Number. Area of the triangle.
- Returns:
- - The height of the triangle.
+ - The height and area of the triangle.
- Example:
- - Gives the height of a triangle at ( 0, 0 ), ( 0, 4 ) and ( 3, 0 ) and a base of 3. The height is 4.
- - `Height = MLib.Polygon.GetTriangleHeight( 3, 0, 0, 0, 4, 3, 0 )`
- - Gives the height of a triangle with a base of 3 and a and area of 6. The height is 4.
- - `Height = MLib.Polygon.GetTriangleHeight( 3, 6 )
+ - Gives the height of a triangle at ( 0, 0 ), ( 0, 4 ) and ( 3, 0 ) and a base of 3. The height is 4, area is 6.
+ - `Height, Area = MLib.Polygon.GetTriangleHeight( 3, 0, 0, 0, 4, 3, 0 )`
+ - Gives the height of a triangle with a base of 3 and an area of 6. The height is 4.
+ - `Height, Area = MLib.Polygon.GetTriangleHeight( 3, 6 )`
#####MLib.Polygon.GetSignedArea
-- Gives the area of any simple polygon.
+- Gives the signed area of any simple polygon.
- Synopsis:
- `MLib.Polygon.GetArea( Verticies )`
- Arguments:
@@ -434,10 +444,10 @@ Handles polygon-related functions.
- The centroid x and y of the polygon.
- Example:
- Gives the centroid of the polygon with points at ( 0, 0 ), ( 0, 6 ), ( 3, 0 ), which is at ( 1, 2 )
- - Vverticies = { 0, 0, 0, 6, 3, 0 }`
+ - `Verticies = { 0, 0, 0, 6, 3, 0 }`
- `CentroidX, CentroidY = MLib.Polygon.GetCentroid( Verticies )`
- Gives centroid of a polygon with points at ( 0, 0 ), ( 0, 4 ), ( 4, 4 ), ( 4, 0 )
- - `CentroidX, a = MLib.Polygon.GetCentroid( 0, 0, 0, 4, 4, 4, 4, 0 )`
+ - `CentroidX, CentroidY = MLib.Polygon.GetCentroid( 0, 0, 0, 4, 4, 4, 4, 0 )`
#####MLib.Polygon.CheckPoint
- Checks whether or not a point is inside a simple polygon.
@@ -469,11 +479,11 @@ Handles polygon-related functions.
- `y2`: Number. Another y-coordinate on the line.
- `...`: Table. The points of the polygon.
- Returns:
- - `true` if the line intersects the polygon.
+ - `Collisions`: Table. The spots where the line intersects the polygon if the line intersects the polygon.
- `false` if the line does not intersect the polygon.
- Example:
- - Check if a line with the points ( 3, 7 ) and ( 5, 4 ) intersects with the polygon. It does.
- - `LineIntersects = MLib.Polygon.LineIntersects( 3, 7, 5, 4, 3, 5, 4, 4, 5, 5, 6, 4, 6, 6, 3, 6 )`
+ - Check if a line with the points ( 3, 7 ) and ( 5, 4 ) intersects with the polygon. It does, at ( 3.8, 5.8 ), ( 4.6, 4.6 ).
+ - `Collision = MLib.Polygon.LineIntersects( 3, 7, 5, 4, 3, 5, 4, 4, 5, 5, 6, 4, 6, 6, 3, 6 )`
- Checks if a line with the points ( 2, 5 ) and ( 3, 7 ) intersects with the polygon. It does not.
- `LineIntersects = MLib.Polygon.LineIntersects( 2, 5, 3, 7, 3, 5, 4, 4, 5, 5, 6, 4, 6, 6, 3, 6 )`
@@ -485,13 +495,13 @@ Handles polygon-related functions.
- `Polygon1`: Table. A table containing all of the points of `polygon1` in the form of `( x1, y1, x2, y2, ... )`.
- `Polygon2`: Table. A table containing all of the points of `polygon2` in the form of `( x1, y1, x2, y2, ... )`.
- Returns:
- - `true` if the polygons intersect.
+ - `Collisions`: Table. The spots where the polygon intersects the other polygon if the polygon intersects the other polygon.
- `false` if the polygons don't intersect.
- Example:
- Checks if polygons with points ( 2, 6, ), ( 3, 8 ), ( 4, 6 ) and ( 4, 7 ), ( 3, 9 ), )( 5, 9 ) intersect. They don't.
- - `PolygonIntersecs = MLib.Polygon.PolygonIntersects( { 2, 6, 3, 8, 4, 6 }, { 4, 7, 3, 9, 5, 9 } )`
- - Checks if polygons with points ( 2, 6 ), ( 3, 8 ), ( 4, 6 ) and ( 3, 7 ), ( 2, 9 ), ( 4, 9 ) intersect. They do.
- - `PolygonIntersects = MLib.Polygon.PolygonIntersects( { 2, 6, 3, 8, 4, 6 }, { 3, 7, 2, 9, 4, 9 } )`
+ - `PolygonIntersects = MLib.Polygon.PolygonIntersects( { 2, 6, 3, 8, 4, 6 }, { 4, 7, 3, 9, 5, 9 } )`
+ - Checks if polygons with points ( 2, 6 ), ( 3, 8 ), ( 4, 6 ) and ( 3, 7 ), ( 2, 9 ), ( 4, 9 ) intersect. They do, at, ( 2.75, 7.5 ), ( 3.25, 7.5 ).
+ - `Collisions = MLib.Polygon.PolygonIntersects( { 2, 6, 3, 8, 4, 6 }, { 3, 7, 2, 9, 4, 9 } )`
#####MLib.Polygon.CircleIntersects
- Checks whether or not a circle intersects a polygon.
@@ -504,17 +514,17 @@ Handles polygon-related functions.
- `CircleY`: Number. The y location of the circle center.
- `Radius`: Number. The radius of the circle.
- `Points`: Table. A table containing all of the points of the polygon in the form of `( x1, y1, x2, y2, ... )`
- - `MLib.Polygon.CircleIntersects( CircleX, CircleY, r, ... )`
+ - `MLib.Polygon.CircleIntersects( CircleX, CircleY, Radius, ... )`
- `CircleX`: Number. The x location of the circle center.
- `CircleY`: Number. The y location of the circle center.
- `Radius`: Number. The radius of the circle.
- `...`: Numbers. All of the points of the polygon in the form of `( x1, y1, x2, y2, ... )`
- Returns:
- - `true` if the circle and polygon intersects.
+ - `Collisions`: Table. The spots where the circle intersects the polygon if the circle intersects the polygon.
- `false` if the circle and polygon don't intersect.
- Example:
- - Checks if a circle with a radius of 2 located on ( 3, 5 ) intersects with a polygon with points on ( 2, 6 ), ( 4, 6 ), ( 3, 8 ). It does.
- - `CircleIntersects = MLib.Polygon.CircleIntersects( 3, 5, 2, 2, 6, 4, 6, 3, 8 )`
+ - Checks if a circle with a radius of 2 located on ( 3, 5 ) intersects with a polygon with points on ( 3, 1 ), ( 3, 6 ), ( 7, 4 ). It does, at ( 3, 3 ) and ( 5, 5 ).
+ - `Collisions = MLib.Polygon.CircleIntersects( 3, 5, 2, 3, 1, 3, 6, 7, 4 )`
- Checks if a circle with a radius of 2 located on ( 3, 3 ) intersects with a polygon with points on ( 2, 6 ), ( 4, 6 ), ( 3, 8 ). It does not.
- `CircleIntersects = MLib.Polygon.CircleIntersects( 3, 3, 2, 2, 6, 4, 6, 3, 8 )`
@@ -533,7 +543,7 @@ Handles functions dealing with circles.
- `Area = MLib.Circle.GetArea( 1 )`
#####MLib.Circle.CheckPoint
-- Checks whether or not a point is within a circle.
+- Checks whether or not a point is on the outer-edge of a circle.
- Synopsis:
- `MLib.Circle.CheckPoint( CircleX, CircleY, Radius, x, y )`
- Arguments:
@@ -582,7 +592,7 @@ Handles functions dealing with circles.
- `Slope`: Number. The slope of the line.
- `Intercept`: Number. The y-intercept of the line.
- Returns:
- - `type`:
+ - `Type`:
- String:
- `'Secant'` if the line is a secant to the circle.
- `'Tangent'` if the line is tangentaltangent
@@ -594,29 +604,34 @@ Handles functions dealing with circles.
- `y2`: Number. The second y-coordinate of where the intersection occurs.
- Example:
- A line with points on ( 0, 9 ), ( 6, 9 ), and a circle center on ( 4, 9 ) and a radius of 1.
- - `type, x1, y1, x2, y2 = MLib.Circle.IsLineSecant( 4, 9, 1, 0, 9, 6, 9 )`
- - Output: `'Secant', 3, 9, 5, 9.`
+ - `Type, x1, y1, x2, y2 = MLib.Circle.IsLineSecant( 4, 9, 1, 0, 9, 6, 9 ) }
+ - Output: `'Secant', 3, 9, 5, 9`
- A line with a slope of 0 and a y-intercept of 9 and a a circle center on ( 4, 9 ) and a radius of 1.
- - `type, x1, y1, x2, y2 = MLib.Circle.IsLineSecant( 4, 9, 1, 0, 9 )`
+ - `Type, x1, y1, x2, y2 = MLib.Circle.IsLineSecant( 4, 9, 1, 0, 9 )`
- Output: `'Secant', 3, 9, 5, 9. `
+ - A line with points on ( 0, 8 ), ( 6, 8 ), and a circle center on ( 4, 9 ) and a radius of 1.
+ - `Type, x1, y1, x2, y2 = MLib.Circle.IsLineSecant( 4, 9, 1, 0, 8, 6, 8 )
+ - Output: `'Tangent', 4, 8`
#####MLib.Circle.IsSegmentSecant
- Checks whether the line is a secant, a tangent or neither.
- Synopsis:
- - `MLib.Circle.IsSegmentSecant( cx, cy, r, x1, y1, x2, y2 )`
+ - `MLib.Circle.IsSegmentSecant( CircleX, CircleY, Radius, x1, y1, x2, y2 )`
- Arguments:
- - `cx`: Number. The x-coordinate of the center of the circle.
- - `cy`: Number. The y-coordinate of the center of the circle.
- - `r`: Number. The radius of the circle.
+ - `CircleX`: Number. The x-coordinate of the center of the circle.
+ - `CircleY`: Number. The y-coordinate of the center of the circle.
+ - `Radius`: Number. The radius of the circle.
- `x1`: Number. The first x-coordinate of the line.
- `y1`: Number. The first y-coordinate of the line.
- `x2`: Number. The second x-coordinate of the line.
- `y2`: Number. The second y-coordinate of the line.
- Returns:
- - `type`:
+ - `Type`:
- String:
- `'Secant'` if the line is a secant to the circle.
- - `'Tangent'` if the line is tangentaltangent
+ - `'Tangent'` if the line is tangental tangent
+ - `'Enclosed'` if the line is completely within the circle.
+ - `'Chord'` if the line is exactly on the circle's circumference.
- Boolean:
- `false` if the line is neither a secant not a tangent.
- `x1`: Number. The first x-coordinate of where the intersection occurs.
@@ -625,21 +640,24 @@ Handles functions dealing with circles.
- `y2`: Number. The second y-coordinate of where the intersection occurs.
- Example:
- A line segment with points on ( 0, 9 ), ( 6, 9 ), and a circle center on ( 4, 9 ) and a radius of 1.
- - `type, x1, y1, x2, y2 = MLib.Circle.IsLineSecant( 4, 9, 1, 0, 9, 6, 9 )`
- - Output: `'Secant', 3, 9, 5, 9.`
+ - `Type, x1, y1, x2, y2 = MLib.Circle.IsLineSecant( 4, 9, 1, 0, 9, 6, 9 )`
+ - Output: `'Secant', 3, 9, 5, 9`
#####MLib.Circle.CircleIntersects
- Returns the point that intersects the circles.
- Synopsis:
- - `MLib.Circle.CircleIntersects( cx1, cy1, r1, cx2, cy2, r2 )`
+ - `MLib.Circle.CircleIntersects( CircleX1, CircleY1, Radius1, CircleX2, CircleY2, Radius2 )`
- Arguments:
- - `cx1`: Number. The x-coordinate of the first center circle.
- - `cy1`: Number. The y-coordinate of the first center circle.
- - `r1`: Number. The radius of the first circle.
- - `cx2`: Number. The x-coordinate of the second center circle.
- - `cy2`: Number. The y-coordinate of the second center circle.
- - `r2`: Number. The radius of the first circle.
-- Returns:
+ - `CircleX1`: Number. The x-coordinate of the first center circle.
+ - `CircleY1`: Number. The y-coordinate of the first center circle.
+ - `Radius1`: Number. The radius of the first circle.
+ - `CircleX2`: Number. The x-coordinate of the second center circle.
+ - `CircleY2`: Number. The y-coordinate of the second center circle.
+ - `Radius2`: Number. The radius of the first circle.
+- Returns:
+ - String:
+ - `'Equal'` if the circles have the same x and y and radius.
+ - `'Colinear'` if the circles have the same x and y, but different radii.
- The points where the circles intersect.
- `false` if they don't intersect.
- Example:
@@ -678,7 +696,7 @@ Handles functions dealing with statisticsistics.
- The average of the numbers.
- Example:
- Gets the average of a data set containing the numbers 1, 2, 3, 4, and 5, which is 3.
- - `mean = MLib.Statistics.GetMean( 1, 2, 3, 4, 5 )`
+ - `Mean = MLib.Statistics.GetMean( 1, 2, 3, 4, 5 )`
#####MLib.Statistics.GetMedian
- Gets the median of the data set.
@@ -691,7 +709,7 @@ Handles functions dealing with statisticsistics.
- The median of the numbers.
- Example:
- Gets the median of a data set containing the numbers, 1, 2, 3, 4, and 5, which is 3.
- - `median = .Statistics.GetMedian( 1, 2, 3, 4, 5 )`
+ - `Median = MLib.Statistics.GetMedian( 1, 2, 3, 4, 5 )`
#####MLib.Statistics.GetMode
- Gets the mode of the data set.
@@ -701,12 +719,13 @@ Handles functions dealing with statisticsistics.
- Table. Contains the numbers data.
- Numbers. Can just be the numbers, or the `unpack`ed table containing the numbers.
- Returns:
- - The mode of the numbers and how many times it appears.
- - `false` if bimodial.
- - `false` if no mode.
+ - If there is one mode or more:
+ - `Numbers`: Table. A table in the form `{ Number1, Number2, etc. }`
+ - `Occurrences`: Number. The number of times the number(s) appeared.
+ - `false` if there is not a mode.
- Example:
- Gets the median of a data set containing the numbers, 1, 5, 6, 22, 2, 2, 1, 2, which is 2, which appears 3 times.
- - `mode, times = MLib.Statistics.GetMode( 1, 5, 6, 22, 2, 2, 1, 2 )`
+ - `Modes, Times = MLib.Statistics.GetMode( 1, 5, 6, 22, 2, 2, 1, 2 )`
#####MLib.Statistics.GetRange
- Gets the range of the data set.
@@ -719,7 +738,7 @@ Handles functions dealing with statisticsistics.
- The range of the numbers.
- Example:
- Gets the range of a data set containing the numbers, 1, 2, 3, and 4, which is 3.
- - `range = MLib.Statistics.GetRange( 1, 2, 3, 4 )`
+ - `Range = MLib.Statistics.GetRange( 1, 2, 3, 4 )`
####MLib.Math
Handles functions that have to do with math in general.
@@ -731,23 +750,23 @@ Handles functions that have to do with math in general.
- `number`: Number. The number you are getting the nth root of.
- `root`: Number. The number that is n for the nth root.
- Returns:
- - The number.
+ - The roots of the number (positive, negative).
- Example:
- Gets the square (2) root of 4, which is 2.
- - `root = MLib.Math.GetRoot( 4, 2 ) `
+ - `Root = MLib.Math.GetRoot( 4, 2 ) `
#####MLib.Math.IsPrime
- Checks whether a number or set of numbers is prime or not.
- Synopsis:
- - `MLib.Math.IsPrime( number )`
+ - `MLib.Math.IsPrime( Number )`
- Arguments:
- - `number`: Number. The number that is being checked for prime-ness.
+ - `Number`: Number. The number that is being checked for prime-ness.
- Returns:
- `true` if the number is prime.
- `false` if the number is not prime.
- Example:
- Checks if the number 3 is prime or not. 3 is prime.
- - `prime = MLib.Math.IsPrime( 3 )`
+ - `Prime = MLib.Math.IsPrime( 3 )`
#####MLib.Math.Round
- Rounds a number up or down, depending on which it's closer to.
@@ -764,29 +783,29 @@ Handles functions that have to do with math in general.
#####MLib.Math.GetSummation
- Gives the summation.
- Synopsis:
- - `MLib.Math.GetSummation( start, stop, func )`
+ - `MLib.Math.GetSummation( Start, Stop, Function )`
- Arguments:
- - `start`: Number. Where should the summation begin?
- - `stop`: Number. Where shuld the summation end?
- - `func`: Function. A function that gives the new value to add to the previous. Can have two arguments:
- - `i`: The first argument. Represents the current number
- - `t`: The second argument. Has all the previous values in it.
- - __IMPORTANT__: If you use `t`, your function must have an `if` statisticsement, regarding what to do if there is not a value for that number yet.
+ - `Start`: Number. Where should the summation begin?
+ - `Stop`: Number. Where shuld the summation end?
+ - `Function`: Function. A Functiontion that gives the new value to add to the previous. Can have two arguments:
+ - `Index`: The first argument. Represents the current number
+ - `Previous`: The second argument. Has all the previous values in it.
+ - __IMPORTANT__: If you use `Previous`, your function must have an `if` statement, regarding what to do if there is not a value for that number yet.
- Returns:
- The sum of all of the values.
- Example:
- - Gives the sum of numbers that start at 1 and end at 10, multuplying each time by 2, which is 110.
- - `sum = MLib.Math.GetSummation( 1, 10, function( i ) return ( i * 2 ) end )`
+ - Gives the sum of numbers that start at 1 and end at 10, multiplying each time by 2, which is 110.
+ - `Sum = MLib.Math.GetSummation( 1, 10, function( Index ) return ( Index * 2 ) end )`
- Gives the sum of numbers that start at 1 and end at 5, adding the previous value each time, which is 35.
- - `sum = MLib.Math.GetSummation( 1, 5, function( i, t ) if t[i-1] then return i + t[i-1] else return 1 end end )`
+ - `Sum = MLib.Math.GetSummation( 1, 5, function( Index, Previous ) if Previous[Index - 1] then return Index + Previous[Index - 1] else return 1 end end )`
#####MLib.Math.GetPercentOfChange
- Gives the percent of change from two numbers.
- Synopsis:
- - `MLib.Math.GetPercentOfChange( old, new )`
+ - `MLib.Math.GetPercentOfChange( Old, New )`
- Arguments:
- - `old`: Number. The previous number.
- - `new`: Number. The new number.
+ - `Old`: Number. The previous number.
+ - `New`: Number. The new number.
- Returns:
- The percentage difference from `old` to `new`.
- Example:
@@ -796,14 +815,14 @@ Handles functions that have to do with math in general.
#####MLib.Math.GetPercent
- Gets the percentage of a number.
- Synopsis:
- - `MLib.Math.GetPercent( percent, num )`
+ - `MLib.Math.GetPercent( Percent, Number )`
- Arguments:
- - `percent`: Number. The percentage you are getting of `num`.
- - `num`: Number. The number that is getting changed.
+ - `Percent`: Number. The percentage you are getting of `Number`.
+ - `Number`: Number. The number that is getting changed.
- Returns:
- - `percentage`% of `num`.
+ - `Percentage`% of `Number`.
- Example:
- - 100% of 2 is 4.
+ - 100% of 2 is 2.
- `MLib.Math.GetPercent( 1, 2 )`
#####MLib.Math.GetRootsOfQuadratic
@@ -815,7 +834,8 @@ Handles functions that have to do with math in general.
- `b`: Number. The number that has `x` next to it.
- `c`: Number. The number that has no variable next to it.
- Returns:
- - The value of x.
+ - `false` if the given quadratic has no solution.
+ - The value of x, otherwise.
- Example:
- Gets the x of the quadratic equation `1 * x ^ 2 + 3 * x - 4`, which is -4, 1.
- `x1, x2 = MLib.Math.GetRootsOfQuadratic( 1, 3, -4 )`
@@ -823,15 +843,8 @@ Handles functions that have to do with math in general.
#####MLib.Math.GetAngle
- Gets the angle between two points.
- Synopsis:
- - `MLib.Math.GetAngle( x1, y1, x2, y2, dir )`
- `MLib.Math.GetAngle( x1, y1, x2, y2, x3, y3 )`
- Arguments:
- - `MLib.Math.GetAngle( x1, y1, x2, y2, dir )`
- - `x1`: Number. The x-coordinate of the primary point.
- - `y1`: Number. The y-coordinate of the primary point.
- - `x2`: Number. The x-coordinate of the secondary point.
- - `y2`: Number. The y-coordinate of the secondary point.
- - `dir`: String. Can be `up`, `down`, `left` or `right`. Used for the orientation of the picture. If not applicable, leave blank or make it `up`.
- `MLib.Math.GetAngle( x1, y1, x2, y2, x3, y3 )`
- `x1`: Number. The x-coordinate of the first point.
- `y1`: Number. The y-coordinate of the first point.
@@ -840,9 +853,9 @@ Handles functions that have to do with math in general.
- `x3`: Number. The x-coordinate of the third point.
- `y3`: Number. The y-coordinate of the third point.
- Returns:
- - The angle from point 1 to point 2 (and possibly point 3) in radians.
+ - The angle between point ( 1, 3 ) and ( 3, 1 ) with a vertex of ( 1, 1 ). This is 90 degrees or about 1.57079633 radians.
- Example:
- - `angle = MLib.Math.GetAngle( 0, 0, 3, 3, 'Up' ), 2.35619449 )`
+ - `Angle = MLib.Math.GetAngle( 1, 3, 1, 1, 3, 1 )
###MLib.Shape
Handles shape collision/intersection.
@@ -918,13 +931,14 @@ Handles shape collision/intersection.
- `Shape:Remove( Shapes )`
- Arguments:
- `MLib.Shape.Remove()`
+ - Remove all shapes.
- `MLib.Shape.Remove( Shapes )`
- - `shapes`: Table. A table containing all of the shapes you want to remove.
+ - `Shapes`: Table. A table containing all of the shapes you want to remove.
- `Shape:Remove()`
- - `shape`: Table. The table returned from MLib.Shape.NewShape.
+ - `Shape`: Table. The table returned from MLib.Shape.NewShape.
- `Shape:Remove( Shapes )`
- - `shape`: Table. The table returned from MLib.Shape.NewShape.
- - `shapes`: Table. A table containing all of the shapes you want to remove.
+ - `Shape`: Table. The table returned from MLib.Shape.NewShape.
+ - `Shapes`: Table. A table containing all of the shapes you want to remove.
##MLib.Shape Example
Here is an example of how to use MLib.Shape.
@@ -977,4 +991,4 @@ function love.update( dt )
print( Rectangle.collided, Line.collided, Circle.collided ) --> true, true, false
end
-````
+````
\ No newline at end of file
diff --git a/mlib.lua b/mlib.lua
index 166646c..2019a52 100644
--- a/mlib.lua
+++ b/mlib.lua
@@ -52,6 +52,29 @@ local function SortWithReference( Table, Function )
return Value, Key
end
+local function CheckFuzzy( Number1, Number2 )
+ return ( Number1 - .00001 <= Number2 and Number2 <= Number1 + .00001 )
+end
+
+local function RemoveDuplicates( Table )
+ for Index1 = #Table, 1, -1 do
+ local First = Table[Index1]
+ for Index2 = #Table, 1, -1 do
+ local Second = Table[Index2]
+ if Index1 ~= Index2 then
+ if type( First[1] ) == 'number' and type( Second[1] ) == 'number' and type( First[2] ) == 'number' and type( Second[2] ) == 'number' then
+ if CheckFuzzy( First[1], Second[1] ) and CheckFuzzy( First[2], Second[2] ) then
+ table.remove( Table, Index1 )
+ end
+ elseif First[1] == Second[1] and First[2] == Second[2] then
+ table.remove( Table, Index1 )
+ end
+ end
+ end
+ end
+ return Table
+end
+
-- Lines
function MLib.Line.GetLength( x1, y1, x2, y2 )
return math.sqrt( ( x1 - x2 ) ^ 2 + ( y1 - y2 ) ^ 2 )
@@ -68,6 +91,7 @@ end
function MLib.Line.GetPerpendicularSlope( ... )
local Userdata = CheckUserdata( ... )
+ local Slope
if #Userdata ~= 1 then
Slope = MLib.Line.GetSlope( unpack( Userdata ) )
@@ -82,7 +106,8 @@ end
function MLib.Line.GetPerpendicularBisector( x1, y1, x2, y2 )
local Slope = MLib.Line.GetSlope( x1, y1, x2, y2 )
- return MLib.Line.GetMidpoint( x1, y1, x2, y2 ), MLib.Line.GetPerpendicularSlope( Slope )
+ local MidpointX, MidpointY = MLib.Line.GetMidpoint( x1, y1, x2, y2 )
+ return MidpointX, MidpointY, MLib.Line.GetPerpendicularSlope( Slope )
end
function MLib.Line.GetIntercept( x, y, ... )
@@ -135,7 +160,7 @@ function MLib.Line.GetIntersection( ... )
return x, y
end
-function MLib.Line.GetClosestPoint( px, py, ... )
+function MLib.Line.GetClosestPoint( PerpendicularX, PerpendicularY, ... )
local Userdata = CheckUserdata( ... )
local x1, y1, x2, y2, Slope, Intercept
local x, y
@@ -152,8 +177,8 @@ function MLib.Line.GetClosestPoint( px, py, ... )
elseif Slope == 0 then
x, y = PerpendicularX, y1
else
- PerpendicularSlope = MLib.Line.GetPerpendicularSlope( Slope )
- PerpendicularIntercept = MLib.Line.GetIntercept( PerpendicularX, PerpendicularY, PerpendicularSlope )
+ local PerpendicularSlope = MLib.Line.GetPerpendicularSlope( Slope )
+ local PerpendicularIntercept = MLib.Line.GetIntercept( PerpendicularX, PerpendicularY, PerpendicularSlope )
x, y = MLib.Line.GetIntersection( Slope, Intercept, PerpendicularSlope, PerpendicularIntercept )
end
@@ -217,29 +242,30 @@ function MLib.Line.Segment.GetIntersection( x1, y1, x2, y2, x3, y3, x4, y4 )
if Intercept1 == Intercept2 then
local x = { x1, x2, x3, x4 }
local y = { y1, y2, y3, y4 }
+ local OriginalX = { x1, x2, x3, x4 }
local OriginalY = { y1, y2, y3, y4 }
local Length1, Length2 = MLib.Line.GetLength( x[1], y[1], x[2], y[2] ), MLib.Line.GetLength( x[3], y[3], x[4], y[4] )
local LargestX, LargestXReference = SortWithReference( x, function ( Value1, Value2 ) return Value1 > Value2 end )
+ table.remove( x, LargestXReference )
local LargestY, LargestYReference = SortWithReference( y, function ( Value1, Value2 ) return Value1 > Value2 end )
+ table.remove( y, LargestYReference )
local SmallestX, SmallestXReference = SortWithReference( x, function ( Value1, Value2 ) return Value1 < Value2 end )
- local SmallestY, SmallestYReference = SortWithReference( y, function ( Value1, Value2 ) return Value1 < Value2 end )
-
- table.remove( x, LargestXReference )
table.remove( x, SmallestXReference )
- table.remove( y, LargestYReference )
+ local SmallestY, SmallestYReference = SortWithReference( y, function ( Value1, Value2 ) return Value1 < Value2 end )
table.remove( y, SmallestYReference )
local Distance = MLib.Line.GetLength( x[1], y[1], x[2], y[2] )
if Distance > Length1 or Distance > Length2 then return false end
-
- local Length1 = MLib.Line.GetLength( x[1], OriginalY[1], x[1], OriginalY[2] )
- local Length2 = MLib.Line.GetLength( x[1], OriginalY[3], x[1], OriginalY[4] )
- local Length3 = MLib.Line.GetLength( x[1], y[1], x[2], y[2] )
+
+ local Length3 = MLib.Line.GetLength( OriginalX[LargestXReference], OriginalY[LargestXReference], OriginalX[SmallestXReference], OriginalY[SmallestXReference] )
if Length3 >= Length1 or Length3 >= Length2 then return false end
- return x[1], y[1], x[2], y[2]
+
+ local _, Index = SortWithReference( x, function ( Value1, Value2 ) return Value1 > Value2 end )
+ if Index == 1 then return x[1], y[1], x[2], y[2]
+ else return x[2], y[2], x[1], y[1] end
else
return false
end
@@ -324,14 +350,13 @@ function MLib.Line.Segment.GetIntersection( x1, y1, x2, y2, x3, y3, x4, y4 )
end
-- Polygon
-function MLib.Polygon.GetTriangleHeight( base, ... )
+function MLib.Polygon.GetTriangleHeight( Base, ... )
local Userdata = CheckUserdata( ... )
- local Area = 0
- local Intercept = 0
+ local Area
if #Userdata == 1 then Area = Userdata[1] else Area = MLib.Polygon.GetArea( Userdata ) end
- return ( 2 * Area ) / base, Area
+ return ( 2 * Area ) / Base, Area
end
function MLib.Polygon.GetSignedArea( ... )
@@ -339,7 +364,7 @@ function MLib.Polygon.GetSignedArea( ... )
local Points = {}
for Index = 1, #Userdata, 2 do
- Points[#Points + 1] = { Userdata[a], Userdata[Index + 1] }
+ Points[#Points + 1] = { Userdata[Index], Userdata[Index + 1] }
end
Points[#Points + 1] = {}
@@ -370,7 +395,7 @@ function MLib.Polygon.GetCentroid( ... )
Points[#Points + 1] = {}
Points[#Points][1], Points[#Points][2] = Points[1][1], Points[1][2]
- local Area = GetSignedArea( Userdata ) -- Needs to be signed here in case points are counter-clockwise.
+ local Area = MLib.Polygon.GetSignedArea( Userdata ) -- Needs to be signed here in case points are counter-clockwise.
local CentroidX = ( 1 / ( 6 * Area ) ) * ( MLib.Math.GetSummation( 1, #Points,
function( Index )
@@ -462,24 +487,21 @@ end
function MLib.Polygon.LineIntersects( x1, y1, x2, y2, ... )
local Userdata = CheckUserdata( ... )
local Choices = {}
-
- if MLib.Polygon.CheckPoint( x1, y1, Userdata ) then Choices[#Choices + 1] = { x1, y1 } end
- if MLib.Polygon.CheckPoint( x2, y2, Userdata ) then Choices[#Choices + 1] = { x2, y2 } end
for Index = 1, #Userdata, 2 do
-- if MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, Userdata[Index], Userdata[Index + 1] ) then return true end
if Userdata[Index + 2] then
- local x1, y1, x2, y2 = MLib.Line.Segment.GetIntersection( Userdata[Index], Userdata[Index + 1], Userdata[Index + 2], Userdata[Index + 3], x1, y1, x2, y2 )
- if x2 then Choices[#Choices + 1] = { x1, y1, x2, y2 }
- elseif x1 then Choices[#Choices + 1] = { x1, y1 } end
+ local x, y = MLib.Line.Segment.GetIntersection( Userdata[Index], Userdata[Index + 1], Userdata[Index + 2], Userdata[Index + 3], x1, y1, x2, y2 )
+ if x then Choices[#Choices + 1] = { x, y } end
else
- local x1, y1, x2, y2 = MLib.Line.Segment.GetIntersection( Userdata[Index], Userdata[Index + 1], Userdata[1], Userdata[2], x1, y1, x2, y2 )
- if x2 then Choices[#Choices + 1] = { x1, y1, x2, y2 }
- elseif x1 then Choices[#Choices + 1] = { x1, y1 } end
+ local x, y = MLib.Line.Segment.GetIntersection( Userdata[Index], Userdata[Index + 1], Userdata[1], Userdata[2], x1, y1, x2, y2 )
+ if x then Choices[#Choices + 1] = { x, y } end
end
end
+
+ local Final = RemoveDuplicates( Choices )
- return #Choices > 0 and Choices or false
+ return #Final > 0 and Final or false
end
function MLib.Polygon.PolygonIntersects( Polygon1, Polygon2 )
@@ -521,21 +543,6 @@ function MLib.Polygon.PolygonIntersects( Polygon1, Polygon2 )
end
end
- function RemoveDuplicates( Table ) -- Local because it is very custom-coded.
- for Index1 = #Table, 1, -1 do
- local First = Table[Index1]
- for Index2 = #Table, 1, -1 do
- local Second = Table[Index2]
- if Index1 ~= Index2 then
- if First[1] == Second[1] and First[2] == Second[2] then
- table.remove( Table, Index1 )
- end
- end
- end
- end
- return Table
- end
-
local Final = RemoveDuplicates( Choices )
return #Final > 0 and Final or false
@@ -545,25 +552,43 @@ function MLib.Polygon.CircleIntersects( x, y, Radius, ... )
local Userdata = CheckUserdata( ... )
local Choices = {}
- if MLib.Polygon.CheckPoint( x, y, Userdata ) then Choices[#Choices + 1] = { x, y } end
-
for Index = 1, #Userdata, 2 do
if Userdata[Index + 2] then
- local x1, y1, x2, y2 = MLib.Circle.IsSegmentSecant( x, y, Radius, Userdata[Index], Userdata[Index + 1], Userdata[Index + 2], Userdata[Index + 3] )
+ local Type, x1, y1, x2, y2 = MLib.Circle.IsSegmentSecant( x, y, Radius, Userdata[Index], Userdata[Index + 1], Userdata[Index + 2], Userdata[Index + 3] )
if x2 then
- Choices[#Choices + 1] = { x1, y1 }
- Choices[#Choices + 1] = { x2, y2 }
- elseif x1 then Choices[#Choices + 1] = { x1, y1 } end
+ Choices[#Choices + 1] = { Type, x1, y1, x2, y2 }
+ elseif x1 then Choices[#Choices + 1] = { Type, x1, y1 } end
else
- local x1, y1, x2, y2 = MLib.Circle.IsSegmentSecant( x, y, Radius, Userdata[Index], Userdata[Index + 1], Userdata[1], Userdata[2] )
+ local Type, x1, y1, x2, y2 = MLib.Circle.IsSegmentSecant( x, y, Radius, Userdata[Index], Userdata[Index + 1], Userdata[1], Userdata[2] )
if x2 then
- Choices[#Choices + 1] = { x1, y1 }
- Choices[#Choices + 1] = { x2, y2 }
- elseif x1 then Choices[#Choices + 1] = { x1, y1 } end
+ Choices[#Choices + 1] = { Type, x1, y1, x2, y2 }
+ elseif x1 then Choices[#Choices + 1] = { Type, x1, y1 } end
+ end
+ end
+
+ local function RemoveDuplicates( Table )
+ for Index1 = #Table, 1, -1 do
+ local First = Table[Index1]
+ for Index2 = #Table, 1, -1 do
+ local Second = Table[Index2]
+ if Index1 ~= Index2 then
+ if type( First[1] ) ~= type( Second[1] ) then return false end
+ if type( First[2] ) == 'number' and type( Second[2] ) == 'number' and type( First[3] ) == 'number' and type( Second[3] ) == 'number' then
+ if CheckFuzzy( First[2], Second[2] ) and CheckFuzzy( First[3], Second[3] ) then
+ table.remove( Table, Index1 )
+ end
+ elseif First[1] == Second[1] and First[2] == Second[2] and First[3] == Second[3] then
+ table.remove( Table, Index1 )
+ end
+ end
+ end
end
+ return Table
end
- return #Choices > 0 and Choices or false
+ local Final = RemoveDuplicates( Choices )
+
+ return #Final > 0 and Final or false
end
-- Circle
@@ -636,35 +661,30 @@ function MLib.Circle.IsSegmentSecant( CircleX, CircleY, Radius, x1, y1, x2, y2 )
local Slope, Intercept = MLib.Line.GetSlope( x1, y1, x2, y2 ), MLib.Line.GetIntercept( x1, y1, x2, y2 )
+ if MLib.Circle.CheckPoint( CircleX, CircleY, Radius, x1, y1 ) and MLib.Circle.CheckPoint( CircleX, CircleY, Radius, x2, y2 ) then -- Both points are on line-segment.
+ return 'Chord', x1, y1, x2, y2
+ end
+
if Slope then
if MLib.Circle.IsPointInCircle( CircleX, CircleY, Radius, x1, y1 ) and MLib.Circle.IsPointInCircle( CircleX, CircleY, Radius, x2, y2 ) then -- Line-segment is fully in circle.
- return x1, y1, x2, y2
+ return 'Enclosed', x1, y1, x2, y2
elseif x3 and x4 then
- if MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x3, y3 ) and MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x4, y4 ) then -- Both points are on line-segment.
- return x3, y3, x4, y4
- elseif MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x3, y3 ) then -- Only the first of the points is on the line-segment.
- return x3, y3
- elseif MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x4, y4 ) then -- Only the second of the points is on the line-segment.
- return x4, y4
- else -- Neither of the points are on the line-segment (means that the segment is not on the circle or "encasing" the circle)
+ if MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x3, y3 ) and not MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x4, y4 ) then -- Only the first of the points is on the line-segment.
+ return 'Tangent', x3, y3
+ elseif MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x4, y4 ) and not MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x3, y3 ) then -- Only the second of the points is on the line-segment.
+ return 'Tangent', x4, y4
+ else -- Neither of the points are on the circle (means that the segment is not on the circle, but "encasing" the circle)
local Length = MLib.Line.GetLength( x1, y1, x2, y2 )
- local Distance1 = MLib.Line.GetLength( x1, y1, x3, y3 )
- local Distance2 = MLib.Line.GetLength( x2, y2, x3, y3 )
- local Distance3 = MLib.Line.GetLength( x1, y1, x4, y4 )
- local Distance4 = MLib.Line.GetLength( x2, y3, x4, y4 )
-
- if Length > Distance1 or Length > Distance2 or Length > Distance3 or Length > Distance4 then
- return false
- elseif Length < Distance1 and Length < Distance2 and Length < Distance3 and Length < Distance4 then
- return false
+ if MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x3, y3 ) and MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x4, y4 ) then
+ return 'Secant', x3, y3, x4, y4
else
- return true
+ return false
end
end
elseif not x4 then -- Is a tangent.
if MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, x3, y3 ) then
- return x3, y3
+ return 'Tangent', x3, y3
else -- Neither of the points are on the line-segment (means that the segment is not on the circle or "encasing" the circle).
local Length = MLib.Line.GetLength( x1, y1, x2, y2 )
local Distance1 = MLib.Line.GetLength( x1, y1, x3, y3 )
@@ -675,7 +695,7 @@ function MLib.Circle.IsSegmentSecant( CircleX, CircleY, Radius, x1, y1, x2, y2 )
elseif Length < Distance1 and Length < Distance2 then
return false
else
- return true
+ return 'Tangent', x3, y3
end
end
end
@@ -696,17 +716,17 @@ function MLib.Circle.IsSegmentSecant( CircleX, CircleY, Radius, x1, y1, x2, y2 )
if BottomY ~= TopY then
if MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, TopX, TopY ) and MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, BottomX, BottomY ) then
- return TopX, TopY, BottomX, BottomY
+ return 'Chord', TopX, TopY, BottomX, BottomY
elseif MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, TopX, TopY ) then
- return TopX, TopX
+ return 'Tangent', TopX, TopX
elseif MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, BottomX, BottomY ) then
- return BottomX, BottomY
+ return 'Tangent', BottomX, BottomY
else
return false
end
else
if MLib.Line.Segment.CheckPoint( x1, y1, x2, y2, TopX, TopY ) then
- return TopX, TopY
+ return 'Tangent', TopX, TopY
else
return false
end
@@ -717,11 +737,13 @@ end
function MLib.Circle.CircleIntersects( Circle1CenterX, Circle1CenterY, Radius1, Circle2CenterX, Circle2CenterY, Radius2 )
local Distance = MLib.Line.GetLength( Circle1CenterX, Circle1CenterY, Circle2CenterX, Circle2CenterY )
if Distance > Radius1 + Radius2 then return false end
- if Distance == 0 and Radius1 == Radius2 then return true end
+ if Distance == 0 and Radius1 == Radius2 then return 'Equal' end
local a = ( Radius1 ^ 2 - Radius2 ^ 2 + Distance ^ 2 ) / ( 2 * Distance )
local h = math.sqrt( Radius1 ^ 2 - a ^ 2 )
+ if Circle1CenterX == Circle2CenterX and Circle1CenterY == Circle2CenterY then return 'Colinear' end
+
local p2x = Circle1CenterX + a * ( Circle2CenterX - Circle1CenterX ) / Distance
local p2y = Circle1CenterY + a * ( Circle2CenterY - Circle1CenterY ) / Distance
local p3x = p2x + h * ( Circle2CenterY - Circle1CenterY ) / Distance
@@ -768,38 +790,27 @@ function MLib.Statistics.GetMode( ... )
local Userdata = CheckUserdata( ... )
table.sort( Userdata )
- local Number = { { Userdata[1] } }
- for Index = 2, #Userdata do
- if Userdata[Index] == Number[#Number][1] then
- table.insert( Number[#Number], Userdata[Index] )
- else
- table.insert( Number, { Userdata[Index] } )
- end
+ local Sorted = {}
+ for Index, Value in ipairs( Userdata ) do
+ Sorted[Value] = Sorted[Value] and Sorted[Value] + 1 or 1
end
- local Large = { { #Number[1], Number[1][1] } }
- for Index = 2, #Number do
- if #Number[Index] > Large[1][1] then
- for NextIndex = #Large, 1, -1 do
- table.remove( Large, NextIndex )
- end
- table.insert( Large, { #Number[Index], Number[Index][1] } )
- elseif #Number[Index] == Large[1][1] then
- table.insert( Large, { #Number[Index], Number[Index][1] } )
+ local Occurrences, Least = 0, {}
+ for Index, Value in pairs( Sorted ) do
+ if Value > Occurrences then
+ Least = { Index }
+ Occurrences = Value
+ elseif Value == Occurrences then
+ Least[#Least + 1] = Index
end
end
- if #Large < 1 then
- return false
- elseif #Large > 1 then
- return false
- else
- return Large[1][2], Large[1][1]
- end
+ if #Least >= 1 then return Least, Occurrences
+ else return false end
end
function MLib.Statistics.GetRange( ... )
- local Userdata = {}
+ local Userdata = CheckUserdata( ... )
local Upper, Lower = math.max( unpack( Userdata ) ), math.min( unpack( Userdata ) )
@@ -808,7 +819,8 @@ end
-- Math (homeless functions)
function MLib.Math.GetRoot( Number, Root )
- return Number ^ ( 1 / Root )
+ local Num = Number ^ ( 1 / Root )
+ return Num, -Num
end
function MLib.Math.IsPrime( Number )
@@ -858,7 +870,9 @@ function MLib.Math.GetSummation( Start, Stop, Function )
end
function MLib.Math.GetPercentOfChange( Old, New )
- if Old == 0 then
+ if Old == 0 and New == 0 then
+ return 0
+ elseif Old == 0 then
return false
else
return ( New - Old ) / math.abs( Old )
@@ -866,7 +880,7 @@ function MLib.Math.GetPercentOfChange( Old, New )
end
function MLib.Math.GetPercent( Percent, Number )
- return Percent * math.abs( Number ) + Number
+ return math.abs( Percent ) * Number
end
function MLib.Math.GetRootsOfQuadratic( a, b, c )
@@ -878,32 +892,12 @@ function MLib.Math.GetRootsOfQuadratic( a, b, c )
return ( -b - Discriminant ) / ( 2 * a ), ( -b + Discriminant ) / ( 2 * a )
end
-function MLib.Math.GetAngle( ... )
- local Userdata = CheckUserdata( ... )
- local Angle = 0
-
- if #Userdata <= 5 then
- local x1, y1, x2, y2, Direction = unpack( Userdata )
-
- if not Direction or Direction == 'Up' then Direction = math.rad( 90 )
- elseif Direction == 'Right' then Direction = 0
- elseif Direction == 'Down' then Direction = math.rad( -90 )
- elseif Direction == 'Left' then Direction = math.rad( -180 )
- end
-
- local dx, dy = x2 - x1, y2 - y1
- Angle = math.atan2( dy, dx ) + Direction
- elseif #Userdata == 6 then
- local x1, y1, x2, y2, x3, y3 = unpack( Userdata )
-
- local AB = MLib.Line.GetLength( x1, y1, x2, y2 )
- local BC = MLib.Line.GetLength( x2, y2, x3, y3 )
- local AC = MLib.Line.GetLength( x1, y1, x3, y3 )
-
- Angle = math.acos( ( BC * BC + AB * AB - AC * AC ) / ( 2 * BC * AB ) )
- end
-
- return Angle
+function MLib.Math.GetAngle( x1, y1, x2, y2, x3, y3 )
+ local A = MLib.Line.GetLength( x3, y3, x2, y2 )
+ local B = MLib.Line.GetLength( x1, y1, x2, y2 )
+ local C = MLib.Line.GetLength( x1, y1, x3, y3 )
+
+ return math.acos( ( A ^ 2 + B ^ 2 - C ^ 2 ) / ( 2 * A * B ) )
end
-- Shape
@@ -912,17 +906,17 @@ function MLib.Shape.NewShape( ... )
if #Userdata == 3 then
Userdata.Type = 'Circle'
- Userdata.x, Userdata.y, Userdata.radius = unpack( Userdata )
- Userdata.Area = MLib.Circle.GetArea( Userdata.radius )
+ Userdata.x, Userdata.y, Userdata.Radius = unpack( Userdata )
+ Userdata.Area = MLib.Circle.GetArea( Userdata.Radius )
elseif #Userdata == 4 then
Userdata.Type = 'Line'
Userdata.x1, Userdata.y1, Userdata.x2, Userdata.y2 = unpack( Userdata )
- Userdata.MLib.Line.GetSlope = MLib.Line.GetSlope( unpack( Userdata ) )
- Userdata.MLib.Line.GetIntercept = MLib.Line.GetIntercept( unpack( Userdata ) )
+ Userdata.Slope = MLib.Line.GetSlope( unpack( Userdata ) )
+ Userdata.Intercept = MLib.Line.GetIntercept( unpack( Userdata ) )
else
+ Userdata.Points = Userdata
Userdata.Type = 'Polygon'
Userdata.Area = MLib.Polygon.GetArea( Userdata )
- Userdata.Points = Userdata
end
Userdata.Collided = false
@@ -938,74 +932,58 @@ end
function MLib.Shape.CheckCollisions( Self, ... )
local Userdata = { ... }
- if Type( Self ) == 'table' then -- Using Index Self:table.
- if #Userdata == 0 then -- No arguments (colliding with everything).
+ local function Check( Self, Shape )
+ local Collided = false
+ if not Shape.Removed and not Self.Removed then
+ if Self.Type == 'Line' then
+ if Shape.Type == 'Line' then
+ if MLib.Line.Segment.GetIntersection( Self.x1, Self.y1, Self.x2, Self.y2, Shape.x1, Shape.y1, Shape.x2, Shape.y2 ) then Collided, Self.Collided, Shape.Collided = true, true, true end
+ elseif Shape.Type == 'Polygon' then
+ if MLib.Polygon.LineIntersects( Self.x1, Self.y1, Self.x2, Self.y2, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true, true end
+ elseif Shape.Type == 'Circle' then
+ if MLib.Circle.IsSegmentSecant( Shape.x, Shape.y, Shape.Radius, Self.x1, Self.y1, Self.x2, Self.y2 ) then Collided, Self.Collided, Shape.Collided = true, true, true end
+ end
+ elseif Self.Type == 'Polygon' then
+ if Shape.Type == 'Line' then
+ if MLib.Polygon.LineIntersects( Shape.x1, Shape.y1, Shape.x2, Shape.y2, Self.Points ) then Collided, Self.Collided, Shape.Collided = true, true, true end
+ elseif Shape.Type == 'Polygon' then
+ if MLib.Polygon.PolygonIntersects( Self.Points, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true, true end
+ elseif Shape.Type == 'Circle' then
+ if MLib.Polygon.CircleIntersects( Shape.x, Shape.y, Shape.Radius, Self.Points ) then Collided, Self.Collided, Shape.Collided = true, true, true end
+ end
+ elseif Self.Type == 'Circle' then
+ if Shape.Type == 'Line' then
+ if MLib.Circle.IsSegmentSecant( Self.x, Self.y, Self.Radius, Shape.x1, Shape.y1, Shape.x2, Shape.y2 ) then Collided, Self.Collided, Shape.Collided = true, true, true end
+ elseif Shape.Type == 'Polygon' then
+ if MLib.Polygon.CircleIntersects( Self.x, Self.y, Self.Radius, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true, true end
+ elseif Shape.Type == 'Circle' then
+ if MLib.Circle.CircleIntersects( Self.x, Self.y, Self.Radius, Shape.x, Shape.y, Shape.Radius ) then Collided, Self.Collided, Shape.Collided = true, true, true end
+ end
+ end
+ end
+ if not Collided then Self.Collided = false end
+ end
+
+ if type( Self ) == 'table' then -- Using Index Self:table.
+ if #Userdata == 0 and Self.Type then -- No arguments (colliding with everything).
for Index = 1, #MLib.Shape.User do
if Index ~= Self.Index then
- local Collided = false
local Shape = MLib.Shape.User[Index]
- if not Shape.Removed and not Self.Removed then
- if Self.Type == 'Line' then
- if Shape.Type == 'Line' then
- if MLib.Line.Segment.GetIntersection( Self.x1, Self.y1, Self.x2, Self.y2, Shape.x1, Shape.y1, Shape.x2, Shape.y2 ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.LineIntersects( Self.x1, Self.y1, Self.x2, Self.y2, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Circle.IsSegmentSecant( Shape.x, Shape.y, Shape.radius, Self.x1, Self.y1, Self.x2, Self.y2 ) then Collided, Self.Collided, Shape.Collided = true, true end
- end
- elseif Self.Type == 'Polygon' then
- if Shape.Type == 'Line' then
- if MLib.Polygon.LineIntersects( Shape.x1, Shape.y1, Shape.x2, Shape.y2, Self.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.PolygonIntersects( Self.Points, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Polygon.CircleIntersects( Shape.x, Shape.y, Shape.radius, Self.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- end
- elseif Self.Type == 'Circle' then
- if Shape.Type == 'Line' then
- if MLib.Circle.IsSegmentSecant( Self.x, Self.y, Self.radius, Shape.x1, Shape.y1, Shape.x2, Shape.y2 ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.CircleIntersects( Self.x, Self.y, Self.radius, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Circle.CircleIntersects( Self.x, Self.y, Self.radius, Shape.x, Shape.y, Shape.radius ) then Collided, Self.Collided, Shape.Collided = true, true end
- end
- end
+ Check( Self, Shape )
+ end
+ end
+ elseif not Self.Type then -- Multi-item table.
+ for Index1, Primary in ipairs( Self ) do
+ for Index2, Secondary in ipairs( Self ) do
+ if Index1 ~= Index2 then
+ Check( Primary, Secondary )
end
- if not Collided then Self.Collided = false end
end
end
else -- Colliding with only certain things.
for Index = 1, #Userdata do
- local Collided = false
local Shape = Userdata[Index]
- if not Shape.Removed and not Self.Removed then
- if Self.Type == 'Line' then
- if Shape.Type == 'Line' then
- if MLib.Line.Segment.GetIntersection( Self.x1, Self.y1, Self.x2, Self.y2, Shape.x1, Shape.y1, Shape.x2, Shape.y2 ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.LineIntersects( Self.x1, Self.y1, Self.x2, Self.y2, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Circle.IsSegmentSecant( Shape.x, Shape.y, Shape.radius, Self.x1, Self.y1, Self.x2, Self.y2 ) then Collided, Self.Collided, Shape.Collided = true, true end
- end
- elseif Self.Type == 'Polygon' then
- if Shape.Type == 'Line' then
- if MLib.Polygon.LineIntersects( Shape.x1, Shape.y1, Shape.x2, Shape.y2, Self.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.PolygonIntersects( Self.Points, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Polygon.CircleIntersects( Shape.x, Shape.y, Shape.radius, Self.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- end
- elseif Self.Type == 'Circle' then
- if Shape.Type == 'Line' then
- if MLib.Circle.IsSegmentSecant( Self.x, Self.y, Self.radius, Shape.x1, Shape.y1, Shape.x2, Shape.y2 ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.CircleIntersects( Self.x, Self.y, Self.radius, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Circle.CircleIntersects( Self.x, Self.y, Self.radius, Shape.x, Shape.y, Shape.radius ) then Collided, Self.Collided, Shape.Collided = true, true end
- end
- end
- end
- if not Collided then Self.Collided = false end
+ Check( Self, Shape )
end
end
else -- Not using Self:table.
@@ -1017,36 +995,9 @@ function MLib.Shape.CheckCollisions( Self, ... )
for Index2 = 1, #MLib.Shape.User do
if Index ~= Index2 then
local Shape = MLib.Shape.User[Index2]
- if not Shape.Removed and not Self.Removed then
- if Self.Type == 'Line' then
- if Shape.Type == 'Line' then
- if MLib.Line.Segment.GetIntersection( Self.x1, Self.y1, Self.x2, Self.y2, Shape.x1, Shape.y1, Shape.x2, Shape.y2 ) then Collided, Self.Collided, Shape.Collided = true, true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.LineIntersects( Self.x1, Self.y1, Self.x2, Self.y2, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Circle.IsSegmentSecant( Shape.x, Shape.y, Shape.radius, Self.x1, Self.y1, Self.x2, Self.y2 ) then Collided, Self.Collided, Shape.Collided = true, true, true end
- end
- elseif Self.Type == 'Polygon' then
- if Shape.Type == 'Line' then
- if MLib.Polygon.LineIntersects( Shape.x1, Shape.y1, Shape.x2, Shape.y2, Self.Points ) then Collided, Self.Collided, Shape.Collided = true, true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.PolygonIntersects( Self.Points, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Polygon.CircleIntersects( Shape.x, Shape.y, Shape.radius, Self.Points ) then Collided, Self.Collided, Shape.Collided = true, true, true end
- end
- elseif Self.Type == 'Circle' then
- if Shape.Type == 'Line' then
- if MLib.Circle.IsSegmentSecant( Self.x, Self.y, Self.radius, Shape.x1, Shape.y1, Shape.x2, Shape.y2 ) then Collided, Self.Collided, Shape.Collided = true, true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.CircleIntersects( Self.x, Self.y, Self.radius, Shape.Points ) then Self.Collided, Collided, Self.Collided, Shape.Collided = true, true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Circle.CircleIntersects( Self.x, Self.y, Self.radius, Shape.x, Shape.y, Shape.radius ) then Collided, Self.Collided, Shape.Collided = true, true, true end
- end
- end
- end
+ Check( Self, Shape )
end
end
- if not Collided then Self.Collided = false end
end
else -- Checking only certain collisions
for Index = 1, #Userdata do
@@ -1055,36 +1006,9 @@ function MLib.Shape.CheckCollisions( Self, ... )
for Index2 = 1, #MLib.Shape.User do
if Self.Index ~= Userdata[Index2].Index then
local Shape = MLib.Shape.User[Index2]
- if not Shape.Removed and not Self.Removed then
- if Self.Type == 'Line' then
- if Shape.Type == 'Line' then
- if MLib.Line.Segment.GetIntersection( Self.x1, Self.y1, Self.x2, Self.y2, Shape.x1, Shape.y1, Shape.x2, Shape.y2 ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.LineIntersects( Self.x1, Self.y1, Self.x2, Self.y2, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Circle.IsSegmentSecant( Shape.x, Shape.y, Shape.radius, Self.x1, Self.y1, Self.x2, Self.y2 ) then Collided, Self.Collided, Shape.Collided = true, true end
- end
- elseif Self.Type == 'Polygon' then
- if Shape.Type == 'Line' then
- if MLib.Polygon.LineIntersects( Shape.x1, Shape.y1, Shape.x2, Shape.y2, Self.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.PolygonIntersects( Self.Points, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Polygon.CircleIntersects( Shape.x, Shape.y, Shape.radius, Self.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- end
- elseif Self.Type == 'Circle' then
- if Shape.Type == 'Line' then
- if MLib.Circle.IsSegmentSecant( Self.x, Self.y, Self.radius, Shape.x1, Shape.y1, Shape.x2, Shape.y2 ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Polygon' then
- if MLib.Polygon.CircleIntersects( Self.x, Self.y, Self.radius, Shape.Points ) then Collided, Self.Collided, Shape.Collided = true, true end
- elseif Shape.Type == 'Circle' then
- if MLib.Circle.CircleIntersects( Self.x, Self.y, Self.radius, Shape.x, Shape.y, Shape.radius ) then Collided, Self.Collided, Shape.Collided = true, true end
- end
- end
- end
+ Check( Self, Shape )
end
end
- if not Collided then Self.Collided = false end
end
end
end
@@ -1093,21 +1017,19 @@ end
function MLib.Shape.Remove( Self, ... )
local Userdata = { ... }
- if Type( Self ) == 'table' then
- MLib.Shape.User[Self.Index] = { Removed = false }
+ if type( Self ) == 'table' and Self.Type then
+ Self.Removed = true
if #Userdata > 0 then
for Index = 1, #Userdata do
- MLib.Shape.User[Userdata[Index].Index] = { Removed = true }
+ MLib.Shape.User[Userdata[Index].Index].Removed = true
end
end
else
- if #Userdata > 0 then
- for Index = 1, #Userdata do
- MLib.Shape.User[Userdata[Index].Index] = { Removed = true }
- end
- else
- MLib.Shape.User = {}
+ local Table = #Userdata > 0 and Userdata or ( Self or MLib.Shape.User )
+
+ for Index = 1, #Table do
+ MLib.Shape.User[Table[Index].Index].Removed = true
end
end
end
diff --git a/spec.lua b/spec.lua
index 46288fa..e8020ca 100644
--- a/spec.lua
+++ b/spec.lua
@@ -1,540 +1,733 @@
require 'telescope'
local _ = require 'mlib'
-context( 'The module',
- function()
- before( function() end )
- after( function() end )
-
- local function check_fuzzy( a, b )
- return ( a - .00001 <= b and b <= a + .00001 )
+context( 'MLib', function()
+ before( function() end )
+ after( function() end )
+
+ local function check_fuzzy( a, b )
+ return ( a - .00001 <= b and b <= a + .00001 )
+ end
+
+ local function DeepCompare( Table1, Table2 )
+ if type( Table1 ) ~= type( Table2 ) then return false end
+
+ for Key, Value in pairs( Table1 ) do
+ if ( type( Value ) == 'table' and type( Table2[Key] ) == 'table' ) then
+ if ( not DeepCompare( Value, Table2[Key] ) ) then return false end
+ else
+ if type( Value ) ~= type( Table2[Key] ) then return false end
+ if type( Value ) == 'number' then
+ return check_fuzzy( Value, Table2[Key] )
+ elseif ( Value ~= Table2[Key] ) then return false end
+ end
end
-
- make_assertion( 'fuzzy_equal', 'fuzzy values to be equal to each other',
- function( a, b )
- return check_fuzzy( a, b )
- end
- )
- make_assertion( 'multiple_fuzzy_equal', 'all fuzzy values to equal respective fuzzy value',
- function( a, b )
- for i = 1, #a do
- if type( a[i] ) ~= 'number' then
- if a[i] ~= b[i] then return false end
- else
- if not check_fuzzy( a[i], b[i] ) then
- return false
- end
+ for Key, Value in pairs( Table2 ) do
+ if ( type( Value ) == 'table' and type( Table1[Key] ) == 'table' ) then
+ if ( not DeepCompare( Value, Table1[Key] ) ) then return false end
+ else
+ if type( Value ) ~= type( Table1[Key] ) then return false end
+ if type( Value ) == 'number' then
+ return check_fuzzy( Value, Table1[Key] )
+ elseif ( Value ~= Table1[Key] ) then return false end
+ end
+ end
+ return true
+ end
+
+ make_assertion( 'fuzzy_equal', 'fuzzy values to be equal to each other',
+ function( a, b )
+ return check_fuzzy( a, b )
+ end
+ )
+
+ make_assertion( 'multiple_fuzzy_equal', 'all fuzzy values to equal respective fuzzy value',
+ function( a, b )
+ for i = 1, #a do
+ if type( a[i] ) ~= 'number' then
+ if a[i] ~= b[i] then return false end
+ else
+ if not check_fuzzy( a[i], b[i] ) then
+ return false
end
end
- return true
end
- )
-
- context( 'line.length', function()
- test( 'gives the distance between two coordinates.', function()
- assert_fuzzy_equal( _.line.length( 0, 0, 3, 0 ), 3 )
- assert_fuzzy_equal( _.line.length( 3, 4, 0, 0 ), 5 )
- assert_fuzzy_equal( _.line.length( 5, 4, 6, 1 ), 3.16227766017 )
- assert_fuzzy_equal( _.line.length( 7.48, 2.5, 6.54, 4.54 ), 2.24615226554 )
- end )
-
- test( 'can get the distance between a single point.', function()
- assert_fuzzy_equal( _.line.length( 3, 2, 3, 2 ), 0 )
+ return true
+ end
+ )
+
+ make_assertion( 'tables_fuzzy_equal', 'all table values are equal',
+ function( Table1, Table2 )
+ return DeepCompare( Table1, Table2 )
+ end
+ )
+
+ context( 'Line', function()
+ context( 'GetLength', function()
+ test( 'Gives the length of a line.', function()
+ assert_fuzzy_equal( _.Line.GetLength( 1, 1, 1, 2 ), 1 )
+ assert_fuzzy_equal( _.Line.GetLength( 0, 0, 1, 0 ), 1 )
+ assert_fuzzy_equal( _.Line.GetLength( 4, 4, 7, 8 ), 5 )
+ assert_fuzzy_equal( _.Line.GetLength( 9.3, 7.6, -12, .001 ), 22.61492 )
+ assert_fuzzy_equal( _.Line.GetLength( 4.2, 4.134, 7.2342, -78 ), 82.190025 )
end )
end )
- context( 'line.midpoint', function()
- test( 'gives the midpoint between two coordinates.', function()
- assert_multiple_fuzzy_equal( { _.line.midpoint( 0, 0, 3, 0 ) }, { 1.5, 0 } )
- assert_multiple_fuzzy_equal( { _.line.midpoint( 3, 4, 0, 0 ) }, { 1.5, 2 } )
- assert_multiple_fuzzy_equal( { _.line.midpoint( 5, 4, 6, 1 ) }, { 5.5, 2.5 } )
- assert_multiple_fuzzy_equal( { _.line.midpoint( 7.48, 2.5, 6.54, 4.54 ) }, { 7.01, 3.52 } )
- end )
-
- test( 'can get the midpoint of a single point.', function()
- assert_multiple_fuzzy_equal( { _.line.midpoint( 3, 2, 3, 2 ) }, { 3, 2 } )
+ context( 'GetMidpoint', function()
+ test( 'Gives the midpoint of a line.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetMidpoint( 0, 0, 2, 2 ) }, { 1, 1 } )
+ assert_multiple_fuzzy_equal( { _.Line.GetMidpoint( 4, 4, 7, 8 ) }, { 5.5, 6 } )
+ assert_multiple_fuzzy_equal( { _.Line.GetMidpoint( -1, 2, 3, -6 ) }, { 1, -2 } )
+ assert_multiple_fuzzy_equal( { _.Line.GetMidpoint( 6.4, 3, -10.7, 4 ) }, { -2.15, 3.5 } )
+ assert_multiple_fuzzy_equal( { _.Line.GetMidpoint( 3.14159, 3.14159, 2.71828, 2.71828 ) }, { 2.92993, 2.92993 } )
end )
end )
- context( 'line.slope', function()
- test( 'gives the slope between two points.', function()
- assert_fuzzy_equal( _.line.slope( 0, 0, 3, 0 ), 0 )
- assert_fuzzy_equal( _.line.slope( 3, 4, 0, 0 ), 4 / 3 )
- assert_fuzzy_equal( _.line.slope( 5, 4, 6, 1 ), -3 )
- assert_fuzzy_equal( _.line.slope( 7.48, 2.5, 6.54, 4.54 ), -2.17021276596 )
+ context( 'GetSlope', function()
+ test( 'Gives the slope of a line given two points.', function()
+ assert_fuzzy_equal( _.Line.GetSlope( 1, 1, 2, 2 ), 1 )
+ assert_fuzzy_equal( _.Line.GetSlope( 1, 1, 0, 1 ), 0 )
+ assert_fuzzy_equal( _.Line.GetSlope( 1, 0, 0, 1 ), -1 )
end )
- test( 'returns false if the line is vertical (x1 == x2).', function()
- assert_false( _.line.slope( 3, 2, 3, 4 ) )
+ test( 'Returns false if the slope is vertical.', function()
+ assert_false( _.Line.GetSlope( 1, 0, 1, 5 ) )
+ assert_false( _.Line.GetSlope( -4, 9, -4, 13423 ) )
end )
end )
- context( 'line.perpendicularSlope', function()
- test( 'gives the perpendicular slope using the slope.', function()
- assert_fuzzy_equal( _.line.perpendicularSlope( 4 / 3 ), -.75 )
- assert_fuzzy_equal( _.line.perpendicularSlope( -3 ), 1/3 )
- assert_fuzzy_equal( _.line.perpendicularSlope( -2.17021276596 ), 0.46078431372 )
+ context( 'GetPerpendicularSlope', function()
+ test( 'Gives the perpendicular slope given two points.', function()
+ assert_fuzzy_equal( _.Line.GetPerpendicularSlope( 1, 1, 2, 2 ), -1 )
end )
- test( 'gives the perpendicular slope using the points.', function()
- assert_fuzzy_equal( _.line.perpendicularSlope( 3, 4, 0, 0 ), -.75 )
- assert_fuzzy_equal( _.line.perpendicularSlope( 5, 4, 6, 1 ), 1/3 )
- assert_fuzzy_equal( _.line.perpendicularSlope( 7.48, 2.5, 6.54, 4.54 ), 0.46078431372 )
+ test( 'Gives the perpendicular slope given the slope.', function()
+ assert_fuzzy_equal( _.Line.GetPerpendicularSlope( 2 ), -.5 )
end )
- test( 'gives the perpendicular slope to vertical lines.', function()
- assert_fuzzy_equal( _.line.perpendicularSlope( 1 / 0 ), 0 )
- assert_fuzzy_equal( _.line.perpendicularSlope( 3, 2, 3, 4 ), 0 )
+ test( 'Gives the perpendicular slope if the initial line is vertical.', function()
+ assert_fuzzy_equal( _.Line.GetPerpendicularSlope( 1, 0, 1, 5 ), 0 )
+ assert_fuzzy_equal( _.Line.GetPerpendicularSlope( false ), 0 )
end )
- test( 'returns false if the perpendicular slope if vertical.', function()
- assert_false( _.line.perpendicularSlope( 0 ) )
- assert_false( _.line.perpendicularSlope( 0, 0, 3, 0 ) )
+ test( 'Returns false if the initial slope is horizontal.', function()
+ assert_false( _.Line.GetPerpendicularSlope( 0, 0, 5, 0 ) )
end )
end )
- context( 'line.perpendicularBisector', function()
- test( 'gives the perpendicular bisector.', function()
- assert_multiple_fuzzy_equal( { _.line.perpendicularBisector( 3, 4, 0, 0 ) }, { -.75, 1.5, 2 } )
- assert_multiple_fuzzy_equal( { _.line.perpendicularBisector( 5, 4, 6, 1 ) }, { 1 / 3, 5.5, 2.5 } )
- assert_multiple_fuzzy_equal( { _.line.perpendicularBisector( 7.48, 2.5, 6.54, 4.54 ) }, { .4607843, 7.01, 3.52 } )
+ context( 'GetPerpendicularBisector', function()
+ test( 'Returns the midpoint and perpendicular slope given two points.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetPerpendicularBisector( 1, 1, 3, 3 ) }, { 2, 2, -1 } )
+ assert_multiple_fuzzy_equal( { _.Line.GetPerpendicularBisector( 1, 0, 1, 8 ) }, { 1, 4, 0 } )
+ assert_multiple_fuzzy_equal( { _.Line.GetPerpendicularBisector( 4, 4, 6, 8 ) }, { 5, 6, -.5 } )
end )
- test( 'gives the perpendicular bisector to vertical lines.', function()
- assert_multiple_fuzzy_equal( { _.line.perpendicularBisector( 3, 2, 3, 4 ) }, { 0, 3, 3 } )
- end )
-
- test( 'returns false, x, y if the perpendicular bisector is vertical.', function()
- assert_multiple_fuzzy_equal( { _.line.perpendicularBisector( 0, 0, 3, 0 ) }, { false, 1.5, 0 } )
+ test( 'Returns false and midpoint if original slope is horizontal.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetPerpendicularBisector( 0, 0, 6, 0 ) }, { 3, 0, false } )
+ assert_multiple_fuzzy_equal( { _.Line.GetPerpendicularBisector( 5, 7, 10, 7 ) }, { 7.5, 7, false } )
end )
end )
- context( 'line.intercept', function()
- test( 'gives the y-intercept using the points and slope.', function()
- assert_fuzzy_equal( _.line.intercept( 0, 0, 0 ), 0 )
- assert_fuzzy_equal( _.line.intercept( 3, 4, 4 / 3 ), 0 )
- assert_fuzzy_equal( _.line.intercept( 5, 4, -3 ), 19 )
- assert_fuzzy_equal( _.line.intercept( 7.48, 2.5, -2.17021276596 ), 18.7331914893617 )
+ context( 'GetIntercept', function()
+ test( 'Gives the y-intercept given two points.', function()
+ assert_fuzzy_equal( _.Line.GetIntercept( 0, 0, 1, 1 ), 0 )
+ assert_fuzzy_equal( _.Line.GetIntercept( 2, 3, 4, 9 ), -3 )
end )
- test( 'gives the y-intercept using the points.', function()
- assert_fuzzy_equal( _.line.intercept( 0, 0, 3, 0 ), 0 )
- assert_fuzzy_equal( _.line.intercept( 3, 4, 0, 0 ), 0 )
- assert_fuzzy_equal( _.line.intercept( 5, 4, 6, 1 ), 19 )
- assert_fuzzy_equal( _.line.intercept( 7.48, 2.5, 6.54, 4.54 ), 18.7331914893617 )
+ test( 'Gives the y-intercept given one point and the slope.', function()
+ assert_fuzzy_equal( _.Line.GetIntercept( 0, 0, 1 ), 0 )
end )
- test( 'returns false for vertical lines.', function()
- assert_false( _.line.intercept( 3, 2, 3, 4 ) )
- assert_false( _.line.intercept( 3, 2, false ) )
+ test( 'Returns false if the slope is false.', function()
+ assert_false( _.Line.GetIntercept( 1, 0, 1, 5 ) )
+ assert_false( _.Line.GetIntercept( 0, 0, false ) )
end )
end )
- context( 'line.func.get', function()
- test( 'gives the exponential function of two points.', function()
- assert_multiple_fuzzy_equal( { _.line.func.get( 1, 2, 2, 2 ) }, { 2, 1 } )
- assert_multiple_fuzzy_equal( { _.line.func.get( 2, 10, -1, .5 ) }, { 1.35720199237, 2.71441761659 } )
+ context( 'GetIntersection', function()
+ test( 'Given the slope, y-intercept, and two points of other line.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetIntersection( 1, 0, 1, 0, 0, 1 ) }, { .5, .5 } )
end )
- test( 'returns false if one/both ys is/are <= 0.', function()
- assert_false( _.line.func.get( 0, 1, 1, -3 ) )
- assert_false( _.line.func.get( 5, -2, 3, 3 ) )
+ test( 'Given the slope, y-intercept, the other slope and y-intercept.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetIntersection( 1, 0, -1, 1 ) }, { .5, .5 } )
end )
- test( 'returns false if the xs are the same.', function()
- assert_false( _.line.func.get( 0, 1, 0, 3 ) )
- end )
- end )
-
- context( 'polygon.triangleHeight', function()
- test( 'gives the height of a triangle given the base and area.', function()
- assert_fuzzy_equal( _.polygon.triangleHeight( 4, 10 ), 5 )
- assert_fuzzy_equal( _.polygon.triangleHeight( 5, 10 ), 4 )
+ test( 'Given two points on one line and two on the other.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetIntersection( 1, 1, 0, 0, 1, 0, 0, 1 ) }, { .5, .5 } )
end )
- test( 'gives the height of a triangle given the base and points. Returns height and area.', function()
- assert_multiple_fuzzy_equal( { _.polygon.triangleHeight( 4, 2, 6, 2, 1, 6, 1 ) }, { 5, 10 } )
- assert_multiple_fuzzy_equal( { _.polygon.triangleHeight( 5, 1, 3, 6, 3, 1, 7 ) }, { 4, 10 } )
+ test( 'Works for vertical lines.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetIntersection( 1, 0, 1, 5, 2, 2, 0, 2 ) }, { 1, 2 } )
end )
- test( 'can get the height of non-right triangles.', function()
- assert_fuzzy_equal( _.polygon.triangleHeight( 6.32, 5 ), 1.58227848101 )
- assert_multiple_fuzzy_equal( { _.polygon.triangleHeight( 6.32, 8, 6, 9, 8, 14, 8 ) }, { 1.58227848101, 5 } )
+ test( 'Returns false if the lines are parallel.', function()
+ assert_false( _.Line.GetIntersection( 2, 4, 2, 7 ) )
end )
end )
- context( 'circle.area', function()
- test( 'gives the area of a circle.', function()
- assert_fuzzy_equal( _.circle.area( 1 ), 3.14159265359 )
- assert_fuzzy_equal( _.circle.area( 2 ), 12.5663706144 )
- assert_fuzzy_equal( _.circle.area( 10 ), 314.159265359 )
- assert_fuzzy_equal( _.circle.area( 57 ), 10207.0345315 )
+ context( 'GetClosestPoint', function()
+ test( 'Given the point and two points on the line.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetClosestPoint( 4, 2, 1, 1, 3, 5 ) }, { 2, 3 } )
+ assert_multiple_fuzzy_equal( { _.Line.GetClosestPoint( 3, 5, 3, 0, 2, 2 ) }, { 1, 4 } )
+ assert_multiple_fuzzy_equal( { _.Line.GetClosestPoint( -1, 3, -2, 0, 2, 2 ) }, { 0, 1 } )
+ end )
+
+ test( 'Given the the point and the slope and y-intercept.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetClosestPoint( 4, 2, 2, -1 ) }, { 2, 3 } )
+ assert_multiple_fuzzy_equal( { _.Line.GetClosestPoint( -1, 3, .5, 1 ) }, { 0, 1 } )
end )
end )
- context( 'stats.mean', function()
- test( 'gives the mean (average).', function()
- assert_fuzzy_equal( _.stats.mean( 1, 2, 3, 4, 5 ), 3 )
- assert_fuzzy_equal( _.stats.mean( 5, 4, 1, -7, 0, 19 ), 3 + 2 / 3 )
- assert_fuzzy_equal( _.stats.mean( math.pi, 12, -8 ), 2.38053088453 )
+ context( 'GetSegmentIntersection', function()
+ test( 'Given the end points of the segment and 2 points on the line.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetSegmentIntersection( 3, 6, 5, 8, 3, 8, 5, 6 ) }, { 4, 7 } )
+ assert_multiple_fuzzy_equal( { _.Line.GetSegmentIntersection( 0, 0, 4, 4, 0, 4, 4, 0 ) }, { 2, 2 } )
+ end )
+
+ test( 'Given end points of the segmen and the slope and intercept.', function()
+ assert_multiple_fuzzy_equal( { _.Line.GetSegmentIntersection( 3, 6, 5, 8, -1, 11 ) }, { 4, 7 } )
end )
- test( 'gives the mean with tables.', function()
- assert_fuzzy_equal( _.stats.mean( { 7, 7, 7 } ), 7 )
- assert_fuzzy_equal( _.stats.mean{ 7, 1, 5, 3 }, 4 )
+ test( 'Returns false if they don\'t intersect.', function()
+ assert_false( _.Line.GetSegmentIntersection( 0, 0, 1, 1, 0, 4, 4, 0 ) )
+ assert_false( _.Line.GetSegmentIntersection( 0, 0, 1, 1, -1, 4 ) )
end )
end )
- context( 'stats.median', function()
- test( 'gives the median of the group', function()
- assert_fuzzy_equal( _.stats.median( 1, 2, 3, 4, 5 ), 3 )
+ context( 'Segment', function()
+ context( 'CheckPoint', function()
+ test( 'Returns true if the point is on the segment.', function()
+ assert_true( _.Line.Segment.CheckPoint( 2, 2, 0, 0, 1, 1 ) )
+ assert_true( _.Line.Segment.CheckPoint( 1, 4, 5, 12, 3, 8 ) )
+ assert_true( _.Line.Segment.CheckPoint( -1, 4, 0, 0, -.5, 2 ) )
+ end )
+
+ test( 'Returns false if the point is not on the segment.', function()
+ assert_false( _.Line.Segment.CheckPoint( 2, 2, 0, 0, 3, 1 ) )
+ assert_false( _.Line.Segment.CheckPoint( 1, 4, 5, 12, 3, 9 ) )
+ end )
end )
- test( 'gives the median of the table', function()
- assert_fuzzy_equal( _.stats.median{ 4, 5, 9, 4, 1, 7, 13 }, 5 )
+ context( 'GetIntersection', function()
+ test( 'Returns the point of intersection if they do.', function()
+ assert_multiple_fuzzy_equal( { _.Line.Segment.GetIntersection( 1, 1, 5, 3, 2, 3, 4, 1 ) }, { 3, 2, nil, nil } )
+ assert_multiple_fuzzy_equal( { _.Line.Segment.GetIntersection( 0, 0, 3, 3, 0, 1, 3, 1 ) }, { 1, 1, nil, nil } )
+ end )
+
+ test( 'Returns false if they don\'t.', function()
+ assert_multiple_fuzzy_equal( { _.Line.Segment.GetIntersection( 3, 7, 6, 8, 1, 6, 5, 4 ) }, { false, nil, nil, nil } )
+ end )
+
+ test( 'Return x1, y1, x2, y2 if lines have same slope and intercept.', function()
+ assert_multiple_fuzzy_equal( { _.Line.Segment.GetIntersection( 0, 0, 2, 2, 1, 1, 3, 3 ) }, { 1, 1, 2, 2 } )
+ assert_multiple_fuzzy_equal( { _.Line.Segment.GetIntersection( 0, 1, 4, 1, 2, 1, 3, 1 ) }, { 2, 1, 3, 1 } )
+ end )
end )
-
- test( 'gives the median of an un-sorted group.', function()
- assert_fuzzy_equal( _.stats.median( 5, 7, 3, 1, 10 ), 5 )
+ end )
+ end )
+
+ context( 'Polygon', function()
+ context( 'GetTriangleHeight', function()
+ test( 'Given points of triangle and length of base.', function()
+ assert_multiple_fuzzy_equal( { _.Polygon.GetTriangleHeight( 3, 0, 0, 0, 4, 3, 0 ) }, { 4, 6 } )
+ assert_multiple_fuzzy_equal( { _.Polygon.GetTriangleHeight( 6, -2, 1, 2, 4, 4, 1 ) }, { 3, 9 } )
+ assert_multiple_fuzzy_equal( { _.Polygon.GetTriangleHeight( 3, 1, 1, 3, 4, 0, 4 ) }, { 3, 4.5 } )
end )
- test( 'gives the median of an un-even group.', function()
- assert_fuzzy_equal( _.stats.median( 1, 2, 3, 4, 5, 6 ), 3.5 )
- assert_fuzzy_equal( _.stats.median( 7, 8, 15, 4, 3, 19, 101, 32 ), 11.5 )
+ test( 'Given the length of the base and the area.', function()
+ assert_fuzzy_equal( _.Polygon.GetTriangleHeight( 3, 6 ), 4 )
+ assert_fuzzy_equal( _.Polygon.GetTriangleHeight( 6, 9 ), 3 )
end )
end )
- context( 'stats.mode', function()
- test( 'gives the mode (most common) of the group and # of occurrences', function()
- assert_multiple_fuzzy_equal( { _.stats.mode( 1, 5, 6, 22, 2, 2, 1, 2 ) }, { 2, 3 } )
- end )
-
- test( 'gives the mode and # of occurrences of the table', function()
- assert_multiple_fuzzy_equal( { _.stats.mode{ 91, 0 , 83, 401, 92, 83, 200 } }, { 83, 2 } )
+ context( 'GetSignedArea', function()
+ test( 'Gives the sigend area of the shape. Positive if clockwise.', function()
+ assert_fuzzy_equal( _.Polygon.GetSignedArea( 0, 0, 3, 0, 3, 4, 0, 4 ), 12 )
+ assert_fuzzy_equal( _.Polygon.GetSignedArea( 0, 0, 3, 0, 0, 4 ), 6 )
+ assert_fuzzy_equal( _.Polygon.GetSignedArea( 4, 4, 0, 4, 0, 0, 4, 0 ), 16 )
end )
- test( 'returns false if the group has no mode', function()
- assert_false( _.stats.mode( 1, 5, 6, 8, 23423 ) )
- end )
-
- test( 'returns false if the group is bimodial', function()
- assert_false( _.stats.mode( 1, 23, 5, 23, 1 ) )
- assert_false( _.stats.mode{ 9, 8, 2, 3, 1, 9, 0, 8 } )
+ test( 'Negative if counter clock-wise.', function()
+ assert_fuzzy_equal( _.Polygon.GetSignedArea( 0, 0, 0, 4, 3, 4, 3, 0 ), -12 )
+ assert_fuzzy_equal( _.Polygon.GetSignedArea( 0, 0, 0, 4, 3, 0 ), -6 )
end )
end )
- context( 'stats.range', function()
- test( 'gets range (largest - smallest) of a set of numbers', function()
- assert_fuzzy_equal( _.stats.range( 1, 2, 3, 4 ), 3 )
- assert_fuzzy_equal( _.stats.range( 2, 6, 213, -213 ), 426 )
- assert_fuzzy_equal( _.stats.range( 2, 2, 2, 2 ), 0 )
+ context( 'GetArea', function()
+ test( 'Gives the sigend area of the shape. Positive if clockwise.', function()
+ assert_fuzzy_equal( _.Polygon.GetArea( 0, 0, 3, 0, 3, 4, 0, 4 ), 12 )
+ assert_fuzzy_equal( _.Polygon.GetArea( 0, 0, 3, 0, 0, 4 ), 6 )
+ assert_fuzzy_equal( _.Polygon.GetArea( 4, 4, 0, 4, 0, 0, 4, 0 ), 16 )
end )
- test( 'gets the range of a table', function()
- assert_fuzzy_equal( _.stats.range( { 1, 2, 3, 4 } ), 3 )
- assert_fuzzy_equal( _.stats.range{ 2, 6, 213, -213 }, 426 )
+ test( 'Gives the area of the shape. Negative if counter clock-wise.', function()
+ assert_fuzzy_equal( _.Polygon.GetArea( 0, 0, 0, 4, 3, 4, 3, 0 ), 12 )
+ assert_fuzzy_equal( _.Polygon.GetArea( 0, 0, 0, 4, 3, 0 ), 6 )
end )
end )
- context( 'math.root', function()
- test( 'gives the nth math.root of the first number', function()
- assert_fuzzy_equal( _.math.root( 4, 2 ), 2 )
- assert_fuzzy_equal( _.math.root( 9, 2 ), 3 )
- assert_fuzzy_equal( _.math.root( 125, 3 ), 5 )
- assert_fuzzy_equal( _.math.root( 100000, 5 ), 10 )
- assert_fuzzy_equal( _.math.root( math.pi, math.pi ), 1.43961949585 )
+ context( 'GetCentroid', function()
+ test( 'Gives the x and y of the centroid.', function()
+ assert_multiple_fuzzy_equal( { _.Polygon.GetCentroid( 0, 0, 0, 4, 4, 4, 4, 0 ) }, { 2, 2 } )
+ assert_multiple_fuzzy_equal( { _.Polygon.GetCentroid( 0, 0, 0, 6, 3, 0 ) }, { 1, 2 } )
+ assert_multiple_fuzzy_equal( { _.Polygon.GetCentroid( 2, -1, 2, 1, 1, 2, -1, 2, -2, 1, -2, -1, -1, -2, 1, -2 ) }, { 0, 0 } )
+ assert_multiple_fuzzy_equal( { _.Polygon.GetCentroid( 2, 0, 3, 0, 4, 1, 3, 2, 2, 2, 1, 1 ) }, { 2.5, 1 } )
+ assert_multiple_fuzzy_equal( { _.Polygon.GetCentroid( 3, 5, 2, 2, 4, 2 ) }, { 3, 3 } )
end )
end )
- context( 'math.prime', function()
- test( 'returns true if number is prime, false if composite (not prime)', function()
- assert_true( _.math.prime( 3 ) )
- assert_false( _.math.prime( 4 ) )
- assert_true( _.math.prime( 5 ) )
- assert_false( _.math.prime( 8 ) )
+ context( 'CheckPoint', function()
+ test( 'Returns true if the point is in the polygon.', function()
+ assert_true( _.Polygon.CheckPoint( 2, 2, 0, 0, 0, 4, 4, 4, 4, 0 ) )
+ assert_true( _.Polygon.CheckPoint( 1, 1, 0, 0, 2, 0, 2, 2, 0, 2 ) )
+ assert_true( _.Polygon.CheckPoint( 3, 2, 2, 2, 3, 1, 4, 3, 5, 2, 4, 4 ) )
end )
- test( 'returns false for any non-interger value or value <= 1', function()
- assert_false( _.math.prime( -2 ) )
+ test( 'Returns false if the point is not.', function()
+ assert_false( _.Polygon.CheckPoint( 7, 8, 0, 0, 0, 4, 4, 4, 4, 0 ) )
+ assert_false( _.Polygon.CheckPoint( -1, 1, 0, 0, 2, 0, 2, 2, 0, 2 ) )
end )
end )
- context( 'polygon.area', function()
- test( 'returns the area of a polygon made going clockwise/counter-clockwise.', function()
- assert_fuzzy_equal( _.polygon.area( 2, 2, 2, 5, 5, 5, 5, 2 ), 9 )
- assert_fuzzy_equal( _.polygon.area( 7, 4, 9, 2, 11, 4, 9, 6 ), 8 )
- assert_fuzzy_equal( _.polygon.area( 4, 7, 5, 6, 6, 7, 8, 5, 8, 4, 7, 3, 3, 3, 2, 4, 2, 5 ), 18 )
- assert_fuzzy_equal( _.polygon.area( 2, 2, 3, 3, 2, 4, 2, 6, 1, 7, 2, 7, 4, 6, 5, 7, 7, 4, 5, 5, 4.14, 4.02, 3, 5, 3, 4, 4, 3, 5, 4, 6, 3, 7, 3, 7, 2, 4, 2, 3, 1 ), 16.48 )
+ context( 'LineIntersects', function()
+ test( 'Returns true if the line intersects the polygon.', function()
+ local tab = _.Polygon.LineIntersects( 0, 4, 4, 4, 0, 0, 0, 4, 4, 4, 4, 0 )
+ assert_tables_fuzzy_equal( tab, { { 0, 4 }, { 4, 4 } } )
+ tab = _.Polygon.LineIntersects( 0, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, 0 )
+ assert_tables_fuzzy_equal( tab, { { 0, 4 }, { 4, 0 } } )
end )
- test( 'returns the area of a polygon etc. using a table.', function()
- assert_fuzzy_equal( _.polygon.area{ 2, 2, 2, 5, 5, 5, 5, 2 }, 9 )
- end )
+ test( 'Returns false if the line does not intersect.', function()
+ assert_false( _.Polygon.LineIntersects( 0, 5, 5, 5, 0, 0, 0, 4, 4, 4, 4, 0 ) )
+ end )
+
+ test( 'Works with vertical lines.', function()
+ local tab = _.Polygon.LineIntersects( 0, 0, 0, 4, 0, 0, 0, 4, 4, 4, 4, 0 )
+ assert_tables_fuzzy_equal( tab, { { 0, 4 }, { 0, 0 } } )
+ assert_false( _.Polygon.LineIntersects( -1, 0, -1, 5, 0, 0, 0, 4, 4, 4, 4, 0 ) )
+ end )
end )
- context( 'math.round', function()
- test( 'math.rounds a number (up or down)', function()
- assert_fuzzy_equal( _.math.round( .99999 ), 1 )
- assert_fuzzy_equal( _.math.round( 1 / 3 ), 0 )
- assert_fuzzy_equal( _.math.round( math.pi ), 3 )
- assert_fuzzy_equal( _.math.round( .1908094820398402938402938409234 ), 0 )
- assert_fuzzy_equal( _.math.round( 12345), 12345 )
+ context( 'PolygonIntersects', function()
+ test( 'Returns true if the polygons intersect.', function()
+ local tab = _.Polygon.PolygonIntersects( { 2, 6, 3, 8, 4, 6 }, { 3, 7, 2, 9, 4, 9 } )
+ assert_tables_fuzzy_equal( tab, { { 2.75, 7.5 }, { 3.25, 7.5 } } )
+ tab = _.Polygon.PolygonIntersects( { 3, 5, 4, 4, 3, 3, 2, 3, 1, 4, 1, 2, 3, 2, 5, 4, 3, 6, 1, 6 }, { 0, 6, 4, 5, 2, 4 } )
+ assert_tables_fuzzy_equal( tab, { { 3.33333, 6.66666 }, { 4, 5 }, { 2, 5.5 } } )
+ end )
+
+ test( 'Returns false if the polygons don\'t intersect.', function()
+ assert_false( _.Polygon.PolygonIntersects( { 2, 6, 3, 8, 4, 6 }, { 4, 7, 3, 9, 5, 9 } ) )
+ assert_false( _.Polygon.PolygonIntersects( { 3, 5, 4, 4, 3, 3, 2, 3, 1, 4, 1, 2, 3, 2, 5, 4, 3, 6, 1, 6 }, { 0, 6, 3, 4, 2, 4 } ) )
+ end )
+
+ test( 'Works with vertical lines.', function()
+ local tab = _.Polygon.PolygonIntersects( { 2, 3, 2, 6, 4, 6, 4, 4, 5, 5, 5, 3 }, { 3, 2, 3, 5, 6, 4, 6, 3, 4, 3, 4, 2 } )
+ assert_tables_fuzzy_equal( tab, { { 4, 4.66666 }, { 4.5, 4.5 }, { 5, 4.33333 }, { 5, 3 }, { 3, 3 }, { 4, 3 } } )
end )
end )
- context( 'math.getAngle', function()
- test( 'returns the radians needed to get to start (1st 2), to location (2nd 2), w/ orientation (assumed up).', function()
- assert_fuzzy_equal( _.math.getAngle( 0, 0, 3, 3, 'up' ), 2.35619449 )
- assert_fuzzy_equal( _.math.getAngle( 0, 0, 3, 3, 'right' ), 0.785398163 )
- assert_fuzzy_equal( _.math.getAngle( 0, 0, 3, 3, 'down' ), -0.785398163 )
- assert_fuzzy_equal( _.math.getAngle( 0, 0, 3, 3, 'left' ), -2.35619449 )
+ context( 'CircleIntersects', function()
+ test( 'Returns true if the circle intersects', function()
+ local tab = _.Polygon.CircleIntersects( 3, 5, 2, 3, 1, 3, 6, 7, 4 )
+ assert_tables_fuzzy_equal( tab, { { 'Tangent', 3, 3 }, { 'Tangent', 5, 5 } } )
+ tab = _.Polygon.CircleIntersects( 5, 5, 1, 4, 4, 6, 4, 6, 6, 4, 6 )
+ assert_tables_fuzzy_equal( tab, { { 'Tangent', 5, 4 }, { 'Tangent', 6, 5 }, { 'Tangent', 5, 6 }, { 'Tangent', 4, 5 } } )
+ tab = _.Polygon.CircleIntersects( 3, 4, 2, 3, 3, 2, 4, 3, 5, 4, 4 )
+ assert_tables_fuzzy_equal( tab, { { 'Enclosed', 3, 3, 2, 4 }, { 'Enclosed', 2, 4, 3, 5 }, { 'Enclosed', 3, 5, 4, 4 }, { 'Enclosed', 4, 4, 3, 3 } } )
+ end )
+
+ test( 'Returns false if the circle doesn\'t intersect.', function()
+ assert_false( _.Polygon.CircleIntersects( 9, 9, 2, 3, 1, 3, 6, 7, 4 ) )
+ assert_false( _.Polygon.CircleIntersects( 10, 5, 1, 4, 4, 6, 4, 6, 6, 4, 6 ) )
+ end )
+ end )
+ end )
+
+ context( 'Circle', function()
+ context( 'GetArea', function()
+ test( 'Gives the area of the circle.', function()
+ assert_fuzzy_equal( _.Circle.GetArea( 1 ), 3.14159 )
+ assert_fuzzy_equal( _.Circle.GetArea( 2 ), 12.56637 )
+ assert_fuzzy_equal( _.Circle.GetArea( 5 ), 78.53981 )
+ assert_fuzzy_equal( _.Circle.GetArea( 10 ), 314.15926 )
+ assert_fuzzy_equal( _.Circle.GetArea( 20 ), 1256.63706 )
end )
end )
- context( 'polygon.centroid', function()
- test( 'returns the centroid of a polygon.', function()
- assert_multiple_fuzzy_equal( { _.polygon.centroid( 0, 100, 100, 50, 100, 100 ) }, { 66.666666, 83.333333 } )
- assert_multiple_fuzzy_equal( { _.polygon.centroid( 3, 5, 4, 4, 6, 4, 6, 6, 5, 7, 4, 7 ) }, { 4.666666, 5.38095238 } )
- assert_multiple_fuzzy_equal( { _.polygon.centroid( 2, 2, 5, 2, 6, 3, 6, 4, 5, 5, 2, 5, 2, 4, 4, 4, 5, 3 ) }, { 4.23809523, 3.69047619 } )
- assert_multiple_fuzzy_equal( { _.polygon.centroid( 4, 3, 3, 6, 9, 7, 12, 3, 10, 2, 8, 5, 7, 4, 7, 2, 6, 4, 6, 5, 5, 4, 6, 2, 5, 1, 3, 2 ) }, { 7.012578616, 4.377358490 } )
- assert_multiple_fuzzy_equal( { _.polygon.centroid( 2, 5, 4, 7, 8, 7, 11, 6, 15, 5, 14, 9, 16, 9, 18, 8, 19, 5, 18, 3, 16, 2, 14, 2, 14, 3, 16, 3, 18, 4, 17, 7, 16, 8, 13, 5, 13, 4, 11, 4, 10, 5, 7, 6, 7, 4, 4, 4 ) }, { 10.7810945, 5.57711442786 } )
+ context( 'CheckPoint', function()
+ test( 'Returns true if the point is on the circle.', function()
+ assert_true( _.Circle.CheckPoint( 3, 4, 2, 1, 4 ) )
+ assert_true( _.Circle.CheckPoint( 2, 2, 1, 2, 1 ) )
+ assert_true( _.Circle.CheckPoint( 2, 4, 2, 0, 4 ) )
+ end )
+
+ test( 'Returns false if the point is not on the circle.', function()
+ assert_false( _.Circle.CheckPoint( 3, 4, 2, 2, 4 ) )
+ assert_false( _.Circle.CheckPoint( 2, 2, 1, 2, 2 ) )
end )
end )
- context( 'math.log', function()
- test( 'returns the nth math.logarithm, with n being the second argument.', function()
- assert_fuzzy_equal( _.math.log( 1, 2 ), 0 )
- assert_fuzzy_equal( _.math.log( 2, 2 ), 1 )
- assert_fuzzy_equal( _.math.log( 3, 2 ), 1.584962500721156 )
- assert_fuzzy_equal( _.math.log( 10, 2 ), 3.321928094887362 )
- assert_fuzzy_equal( _.math.log( 5, 3 ), 1.4649735207179 )
- assert_fuzzy_equal( _.math.log( 7, 2 ), 2.807354922057604 )
+ context( 'GetCircumference', function()
+ test( 'Gives the circumference of the circle.', function()
+ assert_fuzzy_equal( _.Circle.GetCircumference( 1 ), 6.28318 )
+ assert_fuzzy_equal( _.Circle.GetCircumference( 2 ), 12.56637 )
+ assert_fuzzy_equal( _.Circle.GetCircumference( 5 ), 31.41592 )
+ assert_fuzzy_equal( _.Circle.GetCircumference( 10 ), 62.83185 )
+ assert_fuzzy_equal( _.Circle.GetCircumference( 20 ), 125.66370 )
end )
end )
- context( 'math.summation', function()
- test( 'returns the sumation.', function()
- assert_fuzzy_equal( _.math.summation( 3, 6, function( i ) return ( i * ( i + 1 ) ) / 2 end ), 52 )
- assert_fuzzy_equal( _.math.summation( 1, 10, function( i ) return ( i * 2 ) end ), 110 )
+ context( 'IsLineSecant', function()
+ test( 'Returns \'Secant\' when intersects twice.', function()
+ assert_multiple_fuzzy_equal( { _.Circle.IsLineSecant( 4, 9, 1, 0, 9, 6, 9 ) }, { 'Secant', 3, 9, 5, 9 } )
+ assert_multiple_fuzzy_equal( { _.Circle.IsLineSecant( 2, 2, 1, 2, 3, 3, 2 ) }, { 'Secant', 2, 3, 3, 2 } )
end )
-
- test( 'can take the previous value in the argument.', function()
- assert_fuzzy_equal( _.math.summation( 1, 5, function( i, t ) if t[i-1] then return i + t[i-1] else return 1 end end ), 35 )
+
+ test( 'Returns \'Tangent\' when intersects once.', function()
+ assert_multiple_fuzzy_equal( { _.Circle.IsLineSecant( 4, 9, 1, 0, 8, 6, 8 ) }, { 'Tangent', 4, 8 } )
+ assert_multiple_fuzzy_equal( { _.Circle.IsLineSecant( 2, 2, 1, 2, 3, 0, 3 ) }, { 'Tangent', 2, 3 } )
end )
- test( 'returns false if math.huge is second argument.', function()
- assert_false( _.math.summation( 1, math.huge, function( i ) return i end ) )
- assert_false( _.math.summation( 1, -math.huge, function( i ) return i end ) )
- end )
+ test( 'Returns \'false\' when neither.', function()
+ assert_false( _.Circle.IsLineSecant( 4, 9, 1, 0, 7, 6, 8 ) )
+ end )
end )
- context( 'math.percentOfChange', function()
- test( 'gives the % of change of two numbers.', function()
- assert_fuzzy_equal( _.math.percentOfChange( 2, 4 ), 1 )
- assert_fuzzy_equal( _.math.percentOfChange( 10, 0 ), -1 )
- assert_fuzzy_equal( _.math.percentOfChange( 40, 40 ), 0 )
+ context( 'IsSegmentSecant', function()
+ test( 'Returns \'Secant\' if the line connects two points.', function()
+ assert_multiple_fuzzy_equal( { _.Circle.IsSegmentSecant( 4, 9, 1, 0, 9, 6, 9 ) }, { 'Secant', 3, 9, 5, 9 } )
end )
- test( 'gets the % of change from negative #s.', function()
- assert_fuzzy_equal( _.math.percentOfChange( -15, 15 ), 2 )
+ test( 'Returns \'Tangent\' if the line attaches only one point.', function()
+ assert_multiple_fuzzy_equal( { _.Circle.IsSegmentSecant( 1, 1, 1, 0, 0, 0, 2 ) }, { 'Tangent', 0, 1 } )
end )
- test( 'returns false if getting from 0.', function()
- assert_false( _.math.percentOfChange( 0, 10 ) )
+ test( 'Returns \'Chord\' if both points are on the circle.', function()
+ assert_multiple_fuzzy_equal( { _.Circle.IsSegmentSecant( 0, 0, 1, -1, 0, 1, 0 ) }, { 'Chord', -1, 0, 1, 0 } )
end )
- end )
-
- context( 'math.percent', function()
- test( 'gives the % of the 2nd number.', function()
- assert_fuzzy_equal( _.math.percent( 1, 2 ), 4 )
- assert_fuzzy_equal( _.math.percent( -1, 10 ), 0 )
- assert_fuzzy_equal( _.math.percent( 0, 40 ), 40 )
- assert_fuzzy_equal( _.math.percent( 2, -15 ), 15 )
- assert_fuzzy_equal( _.math.percent( 10, 0 ), 0 )
+
+ test( 'Returns \'Enclosed\' if the line is within the circle entirely.', function()
+ assert_multiple_fuzzy_equal( { _.Circle.IsSegmentSecant( 0, 0, 2, -1, 0, 1, 0 ) }, { 'Enclosed', -1, 0, 1, 0 } )
end )
- end )
-
- context( 'circle.checkPoint', function()
- test( 'returns true if the point is on the circle.', function()
- assert_true( _.circle.checkPoint( 3, 4, 2, 1, 4 ) )
- assert_false( _.circle.checkPoint( 8, 5, 3, 3, 4 ) )
- assert_false( _.circle.checkPoint( 8, 5, 3, 8, 9 ) )
- assert_true( _.circle.checkPoint( 8, 5, 2, 8, 3 ) )
- assert_true( _.circle.checkPoint( 13, 3, 5, 13, -2 ) )
+
+ test( 'Returns \'false\' if the line doesn\'t touch anywhere.', function()
+ assert_false( _.Circle.IsSegmentSecant( 0, 0, 1, 2, 2, 2, 3 ) )
end )
end )
- context( 'circle.circumference', function()
- test( 'returns the circumference of the circle.', function()
- assert_fuzzy_equal( _.circle.circumference( 1 ), 6.28318530718 )
- assert_fuzzy_equal( _.circle.circumference( 2 ), 12.5663706144 )
- assert_fuzzy_equal( _.circle.circumference( 3 ), 18.8495559215 )
- assert_fuzzy_equal( _.circle.circumference( 4 ), 25.1327412287 )
- assert_fuzzy_equal( _.circle.circumference( 10 ), 62.8318530718 )
+ context( 'CirclesIntersect', function()
+ test( 'Returns true if the point is within the circle.', function()
+ assert_multiple_fuzzy_equal( { _.Circle.CircleIntersects( 0, 0, 4, 0, 4, 8 ) }, { 0, -4, 0, -4 } )
end )
- end )
-
- context( 'math.quadraticFactor', function()
- test( 'returns the 2 solutions for x in the quadratic equation.', function()
- assert_multiple_fuzzy_equal( { _.math.quadraticFactor( 1, 3, -4 ) }, { -4, 1 } )
- assert_multiple_fuzzy_equal( { _.math.quadraticFactor( 2, -4, -3 ) }, { -.58113883, 2.5811388 } )
- assert_multiple_fuzzy_equal( { _.math.quadraticFactor( 2, 5, -3 ) }, { -3, .5 } )
+
+ test( 'Returns \'Equal\' if the circles are the same.', function()
+ assert_equal( _.Circle.CircleIntersects( 0, 0, 4, 0, 0, 4 ), 'Equal' )
end )
- test( 'returns 1 solution for x (if applicable).', function()
- assert_multiple_fuzzy_equal( { _.math.quadraticFactor( 9, 12, 4 ) }, { -2 / 3, -2 / 3 } )
+ test( 'Returns \'Colinear\' if circles have same x and y but not radii.', function()
+ assert_equal( _.Circle.CircleIntersects( 0, 0, 4, 0, 0, 8 ), 'Colinear' )
+ assert_equal( _.Circle.CircleIntersects( 0, 0, 8, 0, 0, 4 ), 'Colinear' )
end )
- test( 'returns false if no solution.', function()
- assert_false( _.math.quadraticFactor( 3, 4, 2 ) )
+ test( 'Returns false if the point is not within the cirlce.', function()
+ assert_false( _.Circle.CircleIntersects( 4, 4, 1, 6, 6, 1 ) )
end )
end )
- context( 'circle.secant', function()
- test( 'returns if line is a secant, tan, or false using slope and y-intercept.', function()
- assert_multiple_fuzzy_equal( { _.circle.secant( 4, 9, 1, 0, 9 ) }, { 'secant', 3, 9, 5, 9 } )
- assert_multiple_fuzzy_equal( { _.circle.secant( 3, 8, 2, 0, 10 ) }, { 'tangent', 3, 10 } )
+ context( 'IsPointInCircle', function()
+ test( 'Returns true if the point is within the circle.', function()
+ assert_true( _.Circle.IsPointInCircle( 0, 0, 2, 1, 1 ) )
+ assert_true( _.Circle.IsPointInCircle( 5, 5, 5, 2, 2 ) )
+ assert_true( _.Circle.IsPointInCircle( -3, 9, 2, -2, 8 ) )
end )
- test( 'returns if line is a secant, tan, or false using 2 points.', function()
- assert_multiple_fuzzy_equal( { _.circle.secant( 4, 9, 1, 0, 9, 6, 9 ) }, { 'secant', 3, 9, 5, 9 } )
- assert_multiple_fuzzy_equal( { _.circle.secant( 3, 8, 2, 0, 10, 3, 10 ) }, { 'tangent', 3, 10 } )
+ test( 'Returns false if the point is not within the cirlce.', function()
+ assert_false( _.Circle.IsPointInCircle( 0, 0, 2, 5, 1 ) )
+ assert_false( _.Circle.IsPointInCircle( -3, 9, 2, -2, 7 ) )
end )
-
- test( 'can get vertical line slope intersections with points.', function()
- assert_multiple_fuzzy_equal( { _.circle.secant( 3, 8, 2, 0, 10, 3, 10 ) }, { 'tangent', 3, 10 } )
+ end )
+ end )
+
+ context( 'Statistics', function()
+ context( 'GetMean', function()
+ test( 'Gives the arithmetic mean of numbers.', function()
+ assert_equal( _.Statistics.GetMean( 1, 2, 3, 4, 5 ), 3 )
+ assert_equal( _.Statistics.GetMean( 10, 10, 10, 10 ), 10 )
end )
end )
- context( 'circle.circlesIntersect', function()
- test( 'returns the points that intersect.', function()
- assert_multiple_fuzzy_equal( { _.circle.circlesIntersect( 1, 1, 1, 2, 2, 1 ) }, { 2, 1, 1, 2 } )
- assert_multiple_fuzzy_equal( { _.circle.circlesIntersect( 1, 1, 1, 4, 4, 3.60555127546 ) }, { 2, 1, 1, 2 } )
+ context( 'GetMedian', function()
+ test( 'Gives the median of numbers.', function()
+ assert_equal( _.Statistics.GetMedian( 1, 2, 3, 4, 5 ), 3 )
end )
- test( 'returns only one set of point if there is only one point of intersection.', function()
- assert_multiple_fuzzy_equal( { _.circle.circlesIntersect( 1, 1, 1, 3, 1, 1 ) }, { 2, 1 } )
+ test( 'Gives average of two numbers if the amount of numbers is even.', function()
+ assert_equal( _.Statistics.GetMedian( 1, 2, 3, 4, 5, 6 ), 3.5 )
end )
- test( 'returns true if the circles are coincident.', function()
- assert_true( _.circle.circlesIntersect( 1, 1, 1, 1, 1, 1 ) )
+ test( 'Works when the numbers aren\'t ordered, too.', function()
+ assert_equal( _.Statistics.GetMedian( 5, 3, 4, 2, 1 ), 3 )
+ assert_equal( _.Statistics.GetMedian( 3, 4, 1, 2, 5, 6 ), 3.5 )
end )
+ end )
+
+ context( 'GetMode', function()
+ test( 'Returns the mode.', function()
+ assert_tables_fuzzy_equal( { _.Statistics.GetMode( math.pi, math.huge, math.pi ) }, { { math.pi }, 2 } )
+ end )
- test( 'returns false if the circles do not collide anywhere,', function()
- assert_false( _.circle.circlesIntersect( 5, 6, 1, 90, 2, 1 ) )
+ test( 'Works if it\'s bimodial, too', function()
+ assert_tables_fuzzy_equal( { _.Statistics.GetMode( 2, 2, 1, 1, 3 ) }, { { 1, 2 }, 2 } )
+ end )
+ end )
+
+ context( 'GetRange', function()
+ test( 'Returns the range.', function()
+ assert_equal( _.Statistics.GetRange( 1, 2, 3, 4 ), 3 )
+ assert_equal( _.Statistics.GetRange( 100, 5, 3, 6, 7 ), 97 )
+ end )
+ end )
+ end )
+
+ context( 'Math', function()
+ context( 'GetRoot', function()
+ test( 'Gives the nth root to x, given n and x.', function()
+ assert_multiple_fuzzy_equal( { _.Math.GetRoot( 4, 2 ) }, { 2, -2 } )
+ assert_multiple_fuzzy_equal( { _.Math.GetRoot( 16, 2 ) }, { 4, -4 } )
+ assert_multiple_fuzzy_equal( { _.Math.GetRoot( 4, -2 ) }, { .5, -.5 } )
end )
end )
- context( 'line.segment.checkPoint', function()
- test( 'returns true if the point is on the line segment.', function()
- assert_true( _.line.segment.checkPoint( 0, 0, 2, 2, 1, 1 ) )
- assert_true( _.line.segment.checkPoint( 2, 4, 4, 6, 3, 5 ) )
- assert_true( _.line.segment.checkPoint( 1, 1, 3, 1, 2, 1 ) )
+ context( 'IsPrime', function()
+ test( 'Returns true if a number is prime.', function()
+ assert_true( _.Math.IsPrime( 3 ) )
+ assert_true( _.Math.IsPrime( 2 ) )
+ assert_true( _.Math.IsPrime( 47 ) )
end )
- test( 'returns false if the point is not on the line segment.', function()
- assert_false( _.line.segment.checkPoint( 0, 0, 2, 2, 1, 2 ) )
- assert_false( _.line.segment.checkPoint( 1, 1, 3, 1, 4, 1 ) )
+ test( 'Returns false if a number is not prime.', function()
+ assert_false( _.Math.IsPrime( 1 ) )
+ assert_false( _.Math.IsPrime( 100 ) )
end )
end )
- context( 'line.intersect', function()
- test( 'returns the x and y where the lines intersect.', function()
- assert_multiple_fuzzy_equal( { _.line.intersect( 1, 0, -1, 2 ) }, { 1, 1 } )
- assert_multiple_fuzzy_equal( { _.line.intersect( 1, 0, 2, 0, 0, 2 ) }, { 1, 1 } )
+ context( 'Round', function()
+ test( 'Rounds down if the number is less than .5.', function()
+ assert_equal( _.Math.Round( 3.4 ), 3 )
end )
- test( 'can accept lines without a slope, too.', function()
- assert_multiple_fuzzy_equal( { _.line.intersect( 0, 2, 2, 1, 2, 3 ) }, { 2, 2 } )
+ test( 'Rounds up if the number is more than .5.', function()
+ assert_equal( _.Math.Round( 6.7 ), 7 )
end )
- test( 'returns false if lines are parallel.', function()
- assert_false( _.line.intersect( 1, 1, 1, 2 ) )
- assert_false( _.line.intersect( 5, 0, 5, 6 ) )
+ test( 'Specify the number of decimal places to use.', function()
+ assert_equal( _.Math.Round( 197.88, 2 ), 197.88 )
+ assert_equal( _.Math.Round( 197.88, 1 ), 197.9 )
+ assert_equal( _.Math.Round( 197, -2 ), 200 )
end )
end )
- context( 'line.segment.intersect', function()
- test( 'returns the x and y where the line segments intersect.', function()
- assert_multiple_fuzzy_equal( { _.line.segment.intersect( 1, 1, 5, 3, 2, 3, 4, 1 ) }, { 3, 2 } )
- assert_multiple_fuzzy_equal( { _.line.segment.intersect( 1, 5, 3, 7, 3, 5, 1, 7 ) }, { 2, 6 } )
+ context( 'Summation', function()
+ test( 'Adds up numbers and such.', function()
+ assert_equal( _.Math.GetSummation( 1, 10, function( i ) return ( i * 2 ) end ), 110 )
end )
- test( 'returns false if off line segment.', function()
- assert_false( _.line.segment.intersect( 3, 7, 6, 8, 1, 6, 5, 4 ) )
- assert_false( _.line.segment.intersect( 3, 7, 6, 8, 1, 6, 5, 4 ) )
- assert_false( _.line.segment.intersect( 1, 6, 5, 4, 7, 3, 11, 1 ) )
+ test( 'Can access previous values with second function argument.', function()
+ assert_equal( _.Math.GetSummation( 1, 5, function( i, t ) if t[i-1] then return i + t[i-1] else return 1 end end ), 35 )
end )
end )
- context( 'polygon.checkPoint', function()
- test( 'returns true if the point is in the polygon.', function()
- assert_true( _.polygon.checkPoint( 2, 2, 0, 0, 0, 4, 4, 4, 4, 0 ) )
- assert_true( _.polygon.checkPoint( 2, 4, 4, 2, 3, 3, 2, 3, 2, 2, 1, 2, 1, 5, 4, 5 ) )
- assert_true( _.polygon.checkPoint( 7.5, 4.5, 7, 2, 6, 3, 5, 2, 4, 3, 4, 5, 5, 6, 6, 5, 6, 4, 7, 4, 7, 5, 8, 5, 8, 4, 9, 4, 9, 5, 10, 6, 11, 5, 10, 4, 11, 3, 10, 2, 9, 3, 8, 2 ) )
+ context( 'GetPercentOfChange', function()
+ test( 'Gives the percentage of change.', function()
+ assert_equal( _.Math.GetPercentOfChange( 2, 4 ), 1 )
+ assert_equal( _.Math.GetPercentOfChange( 4, 2 ), -.5 )
+ assert_equal( _.Math.GetPercentOfChange( 4, 0 ), -1 )
+ assert_equal( _.Math.GetPercentOfChange( 0, 0 ), 0 )
end )
- test( 'returns false if the point is outside the polygon.', function()
- assert_false( _.polygon.checkPoint( 7, 8, 0, 0, 0, 4, 4, 4, 4, 0 ) )
- assert_false( _.polygon.checkPoint( 3, 2, 4, 2, 3, 3, 2, 3, 2, 2, 1, 2, 1, 5, 4, 5 ) )
+ test( 'False if original is 0.', function()
+ assert_false( _.Math.GetPercentOfChange( 0, 3 ) )
end )
end )
- context( 'line.closestPoint', function()
- test( 'returns the closest point to the line.', function()
- assert_multiple_fuzzy_equal( { _.line.closestPoint( 4, 2, 1, 1, 3, 5 ) }, { 2, 3 } )
- assert_multiple_fuzzy_equal( { _.line.closestPoint( 9, 0, 4, 5, 5, 2 ) }, { 6, -1 } )
- assert_multiple_fuzzy_equal( { _.line.closestPoint( 4, 8, 2, 8, 4, 6 ) }, { 3, 7 } )
- assert_multiple_fuzzy_equal( { _.line.closestPoint( 3, 4, 2, 3, 4, 3 ) }, { 3, 3 } )
- assert_multiple_fuzzy_equal( { _.line.closestPoint( 3, 3, 2, 4, 2, 2 ) }, { 2, 3 } )
+ context( 'GetPercent', function()
+ test( 'Gives the percent.', function()
+ assert_equal( _.Math.GetPercent( 1, 2 ), 2 )
+ assert_equal( _.Math.GetPercent( 2, 1 ), 2 )
+ assert_equal( _.Math.GetPercent( .5, 50 ), 25 )
+ assert_equal( _.Math.GetPercent( 50, 2 ), 100 )
+ assert_equal( _.Math.GetPercent( -.5, 4 ), 2 )
end )
end )
- context( 'line.segmentIntersects.', function()
- test( 'returns the x and y if the line segment intersects.', function()
- assert_multiple_fuzzy_equal( { _.line.segmentIntersects( 3, 6, 5, 8, 3, 8, 5, 6 ) }, { 4, 7 } )
- end )
-
- test( 'returns the x and y of a vertical line.', function()
- assert_multiple_fuzzy_equal( { _.line.segmentIntersects( 0, 3, 2, 5, 1, 1, 1, 5 ) }, { 1, 4 } )
- assert_multiple_fuzzy_equal( { _.line.segmentIntersects( 3, 5, 3, 7, 1, 8, 4, 5 ) }, { 3, 6 } )
+ context( 'GetRootsOfQuadratic', function()
+ test( 'Gives roots given a, b, and c.', function()
+ assert_multiple_fuzzy_equal( { _.Math.GetRootsOfQuadratic( 1, -3, -4 ) }, { -1, 4 } )
+ assert_multiple_fuzzy_equal( { _.Math.GetRootsOfQuadratic( 1, 0, -4 ) }, { -2, 2 } )
+ assert_multiple_fuzzy_equal( { _.Math.GetRootsOfQuadratic( 6, 11, -35 ) }, { -3.5, 5/3 } )
end )
- test( 'returns the x and y of a horizontal line.', function()
- assert_multiple_fuzzy_equal( { _.line.segmentIntersects( 2, 4, 4, 4, 4, 3, 2, 5 ) }, { 3, 4 } )
- assert_multiple_fuzzy_equal( { _.line.segmentIntersects( 4, 6, 8, 8, 5, 8, 9, 8 ) }, { 8, 8 } )
+ test( 'Returns false it has no roots.', function()
+ assert_false( _.Math.GetRootsOfQuadratic( 1, 2, 4 ) )
+ assert_false( _.Math.GetRootsOfQuadratic( .6, .3, .9 ) )
end )
end )
- context( 'polygon.lineIntersects', function()
- test( 'returns true if the line (segment) intersects with the polygon.', function()
- assert_true( _.polygon.lineIntersects( 3, 7, 5, 4, 3, 5, 4, 4, 5, 5, 6, 4, 6, 6, 3, 6 ) )
- assert_true( _.polygon.lineIntersects( 2, 5, 7, 6, 3, 5, 4, 4, 5, 5, 6, 4, 6, 6, 3, 6 ) )
- end )
-
- test( 'returns fasle if the line does not intersect with the polygon.', function()
- assert_false( _.polygon.lineIntersects( 2, 5, 3, 7, 3, 5, 4, 4, 5, 5, 6, 4, 6, 6, 3, 6 ) )
+ context( 'GetAngle', function()
+ test( 'Gives the angle between three points.', function()
+ assert_fuzzy_equal( _.Math.GetAngle( 1, 3, 1, 1, 3, 1 ), 1.57079633 )
+ assert_fuzzy_equal( _.Math.GetAngle( 4, 4, 1, 1, 4, 1 ), 0.785398163 )
end )
end )
-
- context( 'polygon.polygonIntersects', function()
- test( 'returns true if the polygons intersect.', function()
- assert_true( _.polygon.polygonIntersects( { 2, 6, 3, 8, 4, 6 }, { 3, 7, 2, 9, 4, 9 } ) )
+ end )
+
+ context( 'Shape', function()
+ context( 'NewShape', function()
+ test( 'Makes circles if given 3 arguments.', function()
+ assert_tables_fuzzy_equal( { _.Shape.NewShape( 1, 1, 1 ) }, { {
+ 1, 1, 1,
+ Type = 'Circle',
+ x = 1,
+ y = 1,
+ Radius = 1,
+ Area = math.pi,
+ Collided = false,
+ Index = 1,
+ Removed = false,
+ } } )
end )
- test( 'returns false if the polygons don\'t intersect.', function()
- assert_false( _.polygon.polygonIntersects( { 2, 6, 3, 8, 4, 6 }, { 4, 7, 3, 9, 5, 9 } ) )
- end )
- end )
-
- context( 'polygon.circleIntersects', function()
- test( 'returns true if the polygon intersects the circle.', function()
- assert_true( _.polygon.circleIntersects( 3, 5, 2, 2, 6, 4, 6, 3, 8 ) )
+ test( 'Makes lines if given 4 arguments.', function()
+ assert_tables_fuzzy_equal( { _.Shape.NewShape( 1, 1, 0, 0 ) }, { {
+ 1, 1, 0, 0,
+ Type = 'Line',
+ x1 = 1,
+ y1 = 1,
+ x2 = 0,
+ y2 = 0,
+ Slope = 1,
+ Intercept = 0,
+ Collided = false,
+ Index = 1,
+ Removed = false,
+ } } )
end )
- test( 'returns false if the polygon does not intersect the circle.', function()
- assert_false( _.polygon.circleIntersects( 3, 3, 2, 2, 6, 4, 6, 3, 8 ) )
+ test( 'Makes polygons if given more than 4 arguments.', function()
+ assert_tables_fuzzy_equal( { _.Shape.NewShape( -1, -1, -1, 1, 1, 1, 1, -1 ) }, { {
+ -1, -1, -1, 1, 1, 1, 1, -1,
+ Points = { -1, -1, -1, 1, 1, 1, 1, -1 },
+ Type = 'Polygon',
+ Area = 4,
+ Collided = false,
+ Index = 1,
+ Removed = false,
+ } } )
+ end )
+ end )
+
+ context( 'CheckCollisions', function()
+ _.Shape.Remove()
+ local Circle = _.Shape.NewShape( 300, 300, 10 )
+ local Rectangle = _.Shape.NewShape( 400, 300, 400, 200, 600, 200, 600, 300 )
+ local Line = _.Shape.NewShape( 400, 200, 300, 400 )
+
+ local function Reset()
+ _.Shape.Remove()
+ Circle = _.Shape.NewShape( 300, 300, 10 )
+ Rectangle = _.Shape.NewShape( 400, 300, 400, 200, 600, 200, 600, 300 )
+ Line = _.Shape.NewShape( 400, 200, 300, 400 )
+
+ Circle.Collided = false
+ Rectangle.Collided = false
+ Line.Collided = false
+ end
+
+ test( 'When called with no arguments it checks all collisions.', function()
+ Reset()
+ _.Shape.CheckCollisions()
+ assert_true( Rectangle.Collided )
+ assert_true( Line.Collided )
+ assert_false( Circle.Collided )
+ end )
+
+ test( 'A table with arguments only checks mentioned items.', function()
+ Reset()
+ _.Shape.CheckCollisions( { Rectangle, Circle } )
+ assert_false( Rectangle.Collided )
+ assert_false( Line.Collided )
+ assert_false( Circle.Collided )
+
+ Reset()
+ _.Shape.CheckCollisions{ Rectangle, Line }
+ assert_true( Rectangle.Collided )
+ assert_true( Line.Collided )
+ assert_false( Circle.Collided )
+ end )
+
+ test( 'Can use ":" to check collisions on a certain item.', function()
+ Reset()
+ Circle:CheckCollisions()
+ assert_false( Rectangle.Collided )
+ assert_false( Line.Collided )
+ assert_false( Circle.Collided )
+ end )
+
+ test( 'You can also use it to check only certain collisions.', function()
+ Reset()
+ Line:CheckCollisions( Rectangle )
+ assert_true( Rectangle.Collided )
+ assert_true( Line.Collided )
+ assert_false( Circle.Collided )
+ end )
+ end )
+
+ context( 'Remove', function()
+ _.Shape.Remove()
+ local Circle = _.Shape.NewShape( 300, 300, 10 )
+ local Rectangle = _.Shape.NewShape( 400, 300, 400, 200, 600, 200, 600, 300 )
+ local Line = _.Shape.NewShape( 400, 200, 300, 400 )
+
+ local function Reset()
+ _.Shape.Remove()
+ Circle = _.Shape.NewShape( 300, 300, 10 )
+ Rectangle = _.Shape.NewShape( 400, 300, 400, 200, 600, 200, 600, 300 )
+ Line = _.Shape.NewShape( 400, 200, 300, 400 )
+ end
+
+ test( 'No arguments removes all shapes.', function()
+ Reset()
+ _.Shape.Remove()
+ assert_true( Circle.Removed )
+ assert_true( Rectangle.Removed )
+ assert_true( Line.Removed )
+ end )
+
+ test( 'Pass arguments to remove certain shapes.', function()
+ Reset()
+ _.Shape.Remove( { Circle, Rectangle } )
+ assert_true( Circle.Removed )
+ assert_true( Rectangle.Removed )
+ assert_false( Line.Removed )
+ end )
+
+ test( 'Use ":" to remove a single item.', function()
+ Reset()
+ Circle:Remove()
+ assert_true( Circle.Removed )
+ assert_false( Rectangle.Removed )
+ assert_false( Line.Removed )
+ end )
+
+ test( 'Use ":" and a table to remove multiple items.', function()
+ Reset()
+ Circle:Remove( Rectangle )
+ assert_true( Circle.Removed )
+ assert_true( Rectangle.Removed )
+ assert_false( Line.Removed )
end )
end )
- end
-)
\ No newline at end of file
+ end )
+end )
\ No newline at end of file