MLib is a math and shape-intersection detection library written in Lua. It's aim is to be robust and easy to use.
NOTE:
If you are looking for a library that handles updating/collision responses for you, take a look at hxdx. It uses MLib functions as well as Box2d to handle physics calculations.
You can download the latest stable version of MLib by downloading the latest release. You can download the latest working version of MLib by downloading the latest commit. Documentation will only be updated upon releases, not upon commits.
To use MLib, simply place mlib.lua inside the desired folder in your project. Then use the require 'path.to.mlib'
to use any of the functions.
If you don't have LÖVE installed, you can download the .zip of the demo from the Executables folder and extract and run the .exe that way. You can see some examples of the code in action here. All examples are done using the awesome engine of LÖVE. To run them properly, download the .love file and install LÖVE to your computer. After that, make sure you set .love files to open with "love.exe". For more, see here.
Alternatively, you can find the tests here. Keep in mind that you may need to change certain semantics to suit your OS. You can run them via Telescope and type the following command in the command-line of the root folder:
tsc -f specs.lua
If that does not work, you made need to put a link to Lua inside of the folder for telescope
and run the following command:
lua tsc -f specs.lua
If you encounter further errors, try to run the command line as an administrator (usually located in C:\Windows\System32\
), then right-click on cmd.exe
and select Run as administrator
, then do
cd C:\Path\to\telescope\
And then run one of the above commands. If none of those work, just take my word for it that all the tests pass and look at this picture. ![Success](Reference Pictures/Success.png)
onPoint = mlib.line.checkPoint( px, px, x1, y1, x2, y2 )
px
, py
: Numbers. The x and y coordinates of the point being tested.x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates of the line being tested.onPoint
: Boolean.true
if the point is on the line.false
if it does not.mlib.line.checkPoint( px, px, slope, intercept )
because this would lead to errors on vertical lines.cx, cy = mlib.line.getClosestPoint( px, py, x1, y1, x2, y2 )
cx, cy = mlib.line.getClosestPoint( px, py, slope, intercept )
x
, y
: Numbers. The x and y coordinates of the point.x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates on the line.slope
, intercept
:false
). The slope and y-intercept of a vertical line.cx
, cy
: Numbers. The closest points that lie on the line to the point.intercept, isVertical = mlib.line.getYIntercept( x1, y1, x2, y2 )
intercept, isVertical = mlib.line.getYIntercept( x1, y1, slope )
x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates that lie on the line.slope
:intercept
:x1
coordinate of the line if the line is vertical.isVertical
:true
if the line is vertical, false
if the line is not vertical.x, y = mlib.line.getIntersection( x1, y1, x2, y2, x3, y3, x4, y4 )
x, y = mlib.line.getIntersection( slope1, intercept1, x3, y3, x4, y4 )
x, y = mlib.line.getIntersection( slope1, intercept1, slope2, intercept2 )
x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates that lie on the first line.x3
, y3
, x4
, y4
: Numbers. Two x and y coordinates that lie on the second line.slope1
, intercept1
:false
). The slope and y-intercept of the first line (if the first line is vertical).slope2
, intercept2
:false
). The slope and y-intercept of the second line (if the second line is vertical).x
, y
:true
, nil
: The lines are collinear.false
, nil
: The lines are parallel and not collinear.x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates.length
: Number. The distance between the two points.x, y = mlib.line.getMidpoint( x1, y1, x2, y2 )
x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates.x
, y
: Numbers. The midpoint x and y coordinates.perpSlope = mlib.line.getPerpendicularSlope( x1, y1, x2, y2 )
perpSlope = mlib.line.getPerpendicularSlope( slope )
x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates.slope
: Number. The slope of the line.perpSlope
:false
). The perpendicular slope of the line (if the original line was horizontal).x1, y1, x2, y2 = mlib.line.getSegmentIntersection( x1, y1, x2, y2, x3, y3, x4, y4 )
x1, y1, x2, y2 = mlib.line.getSegmentIntersection( x1, y1, x2, y2, slope, intercept )
x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates that lie on the line segment.x3
, y3
, x4
, y4
: Numbers. Two x and y coordinates that lie on the line.slope
, intercept
:false
). The slope and y-intercept of the line (if the line is vertical).x1
, y1
, x2
, y2
:nil
), Boolean (nil
).
false
), Boolean (nil
), Boolean (nil
),
nil
). If the line and segment don't intersect.x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates.slope
:false
). The slope of the line (if the line is vertical).onSegment = mlib.segment.checkPoint( px, py, x1 y1, x2, y2 )
px
, py
: Numbers. The x and y coordinates of the point being checked.x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates.onSegment
: Boolean.true
if the point lies on the line segment.false
if the point does not lie on the line segment.x, y, slope = mlib.segment.getPerpendicularBisector( x1, y1, x2, y2 )
x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates.x
, y
: Numbers. The midpoint of the line.slope
:false
). The perpendicular slope of the line (if the original line was horizontal).cx1, cy1, cx2, cy2 = mlib.segment.getIntersection( x1, y1, x2, y2, x3, y3 x4, y4 )
x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates of the first line segment.x3
, y3
, x4
, y4
: Numbers. Two x and y coordinates of the second line segment.cx1
, cy1
, cx2
, cy2
:nil
), Boolean (nil
).
false
), Boolean (nil
), Boolean (nil
) , Boolean (nil
).
inPolygon = mlib.polygon.checkPoint( px, py, vertices )
inPolygon = mlib.polygon.checkPoint( px, py, ... )
px
, py
: Numbers. The x and y coordinate of the point being checked.vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)inPolygon
: Boolean.true
if the point is inside the polygon.false
if the point is not inside the polygon.cx, cy = mlib.polygon.getCentroid( vertices )
cx, cy = mlib.polygon.getCentroid( ... )
vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)cx
, cy
: Numbers. The x and y coordinates of the centroid.intersections = mlib.polygon.getCircleIntersection( cx, cy, radius, vertices )
cx
, cy
: Number. The coordinates of the center of the circle.radius
: Number. The radius of the circle.vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)intersections
: Table. Contains the intersections and type.local tab = _.polygon.getCircleIntersection( 5, 5, 1, 4, 4, 6, 4, 6, 6, 4, 6 )
for i = 1, # tab do
print( i .. ':', unpack( tab[i] ) )
end
-- 1: tangent 5 4
-- 2: tangent 6 5
-- 3: tangent 5 6
-- 4: tagnent 4 5
intersections = mlib.polygon.getLineIntersection( x1, y1, x2, y2, vertices )
x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates.vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)intersections
: Table. Contains the intersections.{ 0, 4, 0, 0 }
would become { 0, 4 }, { 0, 0 }
.area = mlib.polygon.getArea( vertices )
vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)area
: Number. The area of the polygon.intersections = mlib.polygon.getPolygonIntersections( polygon1, polygon2 )
polygon1
: Table. The vertices of the first polygon in the format { x1, y1, x2, y2, x3, y3, ... }
polygon2
: Table. The vertices of the second polygon in the format { x1, y1, x2, y2, x3, y3, ... }
intersections
: Table. A table of the points of intersection.intersections = mlib.polygon.getSegmentIntersection( x1, y1, x2, y2, vertices )
x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates.vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)intersections
: Table. Contains the intersections.area = mlib.polygon.getLineIntersection( vertices )
vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)area
: Number. The signed area of the polygon. If the points are ordered counter-clockwise the area is positive. If the points are ordered clockwise the number is negative.height = mlib.polygon.getTriangleHeigh( base, x1, y1, x2, y2, x3, y3 )
height = mlib.polygon.getTriangleHeight( base, area )
base
: Number. The length of the base of the triangle.x1
, y1
, x2
, y2
, x3
, y3
: Numbers. The x and y coordinates of the triangle.area
: Number. The regular area of the triangle. Not the signed area.height
: Number. The height of the triangle.inPolygon = mlib.polygon.isCircleInside( cx, cy, radius, vertices )
inPolygon = mlib.polygon.isCircleInside( cx, cy, radius, ... )
cx
, cy
: Numbers. The x and y coordinates for the center of the circle.radius
: Number. The radius of the circle.vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)inPolygon
: Boolean.true
if the circle is inside the polygon.false
if the circle is not inside the polygon.inPolygon = mlib.polygon.isCircleCompletelyInside( cx, cy, radius, vertices )
inPolygon = mlib.polygon.isCircleCompletelyInside( cx, cy, radius, ... )
cx
, cy
: Numbers. The x and y coordinates for the center of the circle.radius
: Number. The radius of the circle.vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)inPolygon
: Boolean.true
if the circle is completely inside the polygon.false
if the circle is not inside the polygon.inPolygon = mlib.polygon.isPolygonInside( polygon1, polygon2 )
polygon1
: Table. The vertices of the first polygon in the format { x1, y1, x2, y2, x3, y3, ... }
polygon2
: Table. The vertices of the second polygon in the format { x1, y1, x2, y2, x3, y3, ... }
inPolygon
: Boolean.true
if the polygon2
is inside of polygon1
.false
if polygon2
is not inside of polygon2
.polygon2
are inside of the polygon1
.inPolygon = mlib.polygon.isPolygonCompletelyInside( polygon1, polygon2 )
polygon1
: Table. The vertices of the first polygon in the format { x1, y1, x2, y2, x3, y3, ... }
polygon2
: Table. The vertices of the second polygon in the format { x1, y1, x2, y2, x3, y3, ... }
inPolygon
: Boolean.true
if the polygon2
is completely inside of polygon1
.false
if polygon2
is not inside of polygon2
.inPolygon = mlib.polygon.isSegmentInside( x1, y1, x2, y2, vertices )
inPolygon = mlib.polygon.isSegmentInside( x1, y1, x2, y2, ... )
x1
, y1
, x2
, y2
: Numbers. The x and y coordinates of the line segment.vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)inPolygon
: Boolean.true
if the line segment is inside the polygon.false
if the line segment is not inside the polygon.inPolygon = mlib.polygon.isSegmentCompletelyInside( x1, y1, x2, y2, vertices )
inPolygon = mlib.polygon.isSegmentCompletelyInside( x1, y1, x2, y2, ... )
x1
, y1
, x2
, y2
: Numbers. The x and y coordinates of the line segment.vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)inPolygon
: Boolean.true
if the line segment is completely inside the polygon.false
if the line segment is not inside the polygon.inCircle = mlib.circle.checkPoint( px, px, cx, cy, radius )
px
, py
: Numbers. The x and y coordinates of the point being tested.cx
, cy
: Numbers. The x and y coordinates of the center of the circle.radius
: Number. The radius of the circle.inCircle
: Boolean.true
if the point is inside or on the circle.false
if the point is outside of the circle.area = mlib.circle.getArea( radius )
radius
: Number. The radius of the circle.area
: Number. The area of the circle.c1x
, c1y
: Numbers. The x and y coordinate of the first circle.radius1
: Number. The radius of the first circle.c2x
, c2y
: Numbers. The x and y coordinate of the second circle.radius2
: Number. The radius of the second circle.intersections
: Table. A table that contains the type and where the circle collides. See the specs for more.circumference = mlib.circle.getCircumference( radius )
radius
: Number. The radius of the circle.circumference
: Number. The circumference of a circle.intersections = mlib.circle.getLineIntersections( cx, cy, radius, x1, y1, x2, y2 )
cx
, cy
: Numbers. The x and y coordinates for the center of the circle.radius
: Number. The radius of the circle.x1
, y1
, x2
, y2
: Numbers. Two x and y coordinates the lie on the line.intersections
: Table. A table with the type and where the intersections happened. Table is formatted:type
, x1
, y1
, x2
, y2
'secant'
), Number, Number, Number, Number'tangent'
), Number, Number, Boolean (nil
), Boolean (nil
)x1
and x2
represent where the line intersects the circle.false
), Boolean (nil
), Boolean (nil
), Boolean (nil
), Boolean (nil
)intersections = mlib.circle.getSegmentIntersections( cx, cy, radius, x1, y1, x2, y2 )
cx
, cy
: Numbers. The x and y coordinates for the center of the circle.radius
: Number. The radius of the circle.x1
, y1
, x2
, y2
: Numbers. The two x and y coordinates of the line segment.intersections
: Table. A table with the type and where the intersections happened. Table is formatted:type
, x1
, y1
, x2
, y2
'chord'
), Number, Number, Number, Number'enclosed'
), Number, Number, Number, Number'secant'
), Number, Number, Number, Number'tangent'
), Number, Number, Boolean (nil
), Boolean (nil
)x1
and x2
represent where the line segment intersects the circle.false
), Boolean (nil
), Boolean (nil
), Boolean (nil
), Boolean (nil
)completelyInside = mlib.circle.isCircleCompletelyInside( c1x, c1y, c1radius, c2x, c2y, c2radius )
c1x
, c1y
: Numbers. The x and y coordinates of the first circle.c1radius
: Number. The radius of the first circle.c2x
, c2y
: Numbers. The x and y coordinates of the second circle.c2radius
: Number. The radius of the second circle.completelyInside
: Boolean.true
if circle1 is inside of circle2.false
if circle1 is not completely inside of circle2.inPolygon = mlib.polygon.isCircleCompletelyInside( cx, cy, radius, vertices )
inPolygon = mlib.polygon.isCircleCompletelyInside( cx, cy, radius, ... )
cx
, cy
: Numbers. The x and y coordinates for the center of the circle.radius
: Number. The radius of the circle.vertices
: Table. The vertices of the polygon in the format { x1, y1, x2, y2, x3, y3, ... }
...
: Numbers. The x and y coordinates of the polygon. (Same as using unpack( vertices )
)inPolygon
: Boolean.true
if the circle is completely inside the polygon.false
if the circle is not inside the polygon.onCircle = mlib.circle.checkPoint( px, px, cx, cy, radius )
px
, py
: Numbers. The x and y coordinates of the point being tested.cx
, cy
: Numbers. The x and y coordinates of the center of the circle.radius
: Number. The radius of the circle.onCircle
: Boolean.true
if the point is on the circle.false
if the point is on the inside or outside of the circle.completelyInside = mlib.circle.isPolygonCompletelyInside( circleX, circleY, circleRadius, vertices )
completelyInside = mlib.circle.isPolygonCompletelyInside( circleX, circleY, circleRadius, ... )
circleX
, circleY
: Numbers. The x and y coordinates of the circle.circleRadius
: Number. The radius of the circle.vertices
: Table. A table containing all of the vertices of the polygon....
: Numbers. All of the points of the polygon.completelyInside
: Boolean.true
if the polygon is inside of the circle.false
if the polygon is not completely inside of the circle.modes, occurrences, median, mean = mlib.statistics.getCentralTendency( data )
modes, occurrences, median, mean = mlib.statistics.getCentralTendency( ... )
data
: Table. A table containing the values of data....
: Numbers. All of the numbers in the data set.modes, occurrences
: Table, Number. The modes of the data and the number of times it occurs. See mlib.statistics.getMode.median
: Number. The median of the data set.mean
: Number. The mean of the data set.variationRatio, range, standardDeviation = mlib.statistics.getDispersion( data )
variationRatio, range, standardDeviation = mlib.statistics.getDispersion( ... )
data
: Table. A table containing the values of data....
: Numbers. All of the numbers in the data set.variationRatio
: Number. The variation ratio of the data set.range
: Number. The range of the data set.standardDeviation
: Number. The standard deviation of the data set.mean = mlib.statistics.getMean( data )
mean = mlib.statistics.getMean( ... )
data
: Table. A table containing the values of data....
: Numbers. All of the numbers in the data set.mean
: Number. The arithmetic mean of the data set.median = mlib.statistics.getMedian( data )
median = mlib.statistics.getMedian( ... )
data
: Table. A table containing the values of data....
: Numbers. All of the numbers in the data set.median
: Number. The median of the data.mode, occurrences = mlib.statistics.getMode( data )
mode, occurrences = mlib.statistics.getMode( ... )
data
: Table. A table containing the values of data....
: Numbers. All of the numbers in the data set.mode
: Table. The mode(s) of the data.occurrences
: Number. The number of time the mode(s) occur.range = mlib.statistics.getRange( data )
range = mlib.statistics.getRange( ... )
data
: Table. A table containing the values of data....
: Numbers. All of the numbers in the data set.range
: Number. The range of the data.standardDeviation = mlib.statistics.getStandardDeviation( data )
standardDeviation = mlib.statistics.getStandardDeviation( ... )
data
: Table. A table containing the values of data....
: Numbers. All of the numbers in the data set.standardDeviation
: Number. The standard deviation of the data set.variance = mlib.statistics.getVariance( data )
variance = mlib.statistics.getVariance( ... )
data
: Table. A table containing the values of data....
: Numbers. All of the numbers in the data set.variance
: Number. The variation of the data set.variationRatio = mlib.statistics.getVariationRatio( data )
variationRatio = mlib.statistics.getVariationRatio( ... )
data
: Table. A table containing the values of data....
: Numbers. All of the numbers in the data set.variationRatio
: Number. The variation ratio of the data set.angle = mlib.math.getAngle( x1, y1, x2, y2, x3, y3 )
x1
, y1
: Numbers. The x and y coordinates of the first point.x2
, y2
: Numbers. The x and y coordinates of the vertex of the two points.x3
, y3
: Numbers. The x and y coordinates of the second point.percentage = mlib.math.getPercentage( percent, number )
percent
: Number. The decimal value of the percent (i.e. 100% is 1, 50% is .5).number
: Number. The number to get the percentage of.percentage
: Number. The percent
age or number
.change = mlib.math.getPercentOfChange( old, new )
old
: Number. The original number.new
: Number. The new number.change
: Number. The percent of change from old
to new
.root1, root2 = mlib.math.getQuadraticRoots( a, b, c )
a
, b
, c
: Numbers. The a, b, and c values of the equation a * x ^ 2 + b * x ^ 2 + c
.root1
, root2
: Numbers. The roots of the equation (where a * x ^ 2 + b * x ^ 2 + c = 0
).n
th root of a number.x = mlib.math.getRoot( number, root )
number
: Number. The number to get the root of.root
: Number. The root.x
: The root
th root of number
.
local a = mlib.math.getRoot( 4, 2 ) -- Same as saying 'math.pow( 4, .5 )' or 'math.sqrt( 4 )' in this case.
local b = mlib.math.getRoot( 27, 3 )
print( a, b ) --> 2, 3
- For more, see the [specs](spec.lua).
##### mlib.math.getSummation
- Gets the summation of numbers.
- Synopsis:
- `summation = mlib.math.getSummation( start, stop, func )`
- Arguments:
- `start`: Number. The number at which to start the summation.
- `stop`: Number. The number at which to stop the summation.
- `func`: Function. The method to add the numbers.
- Arguments:
- `i`: Number. Index.
- `previous`: Table. The previous values used.
- Returns:
- `Summation`: Number. The summation of the numbers.
- For more, see the [specs](spec.lua).
##### mlib.math.isPrime
- Checks if a number is prime.
- Synopsis:
- `isPrime = mlib.math.isPrime( x )`
- Arguments:
- `x`: Number. The number to check if it's prime.
- Returns:
- `isPrime`: Boolean.
- `true` if the number is prime.
- `false` if the number is not prime.
##### mlib.math.round
- Rounds a number to the given decimal place.
- Synopsis:
- `rounded = mlib.math.round( number, [place] )
- Arguments:
- `number`: Number. The number to round.
- `place (1)`: Number. The decimal place to round to. Defaults to 1.
- Returns:
- The rounded number.
- For more, see the [specs](spec.lua).
#### Aliases
| Alias | Corresponding Function |
| ----------------------------------------------|:---------------------------------------------------------------------------------:|
| milb.line.getDistance | [mlib.line.getLength](#mliblinegetlength) |
| mlib.line.getCircleIntersection | [mlib.circle.getLineIntersection](#mlibcirclegetlineintersection) |
| milb.line.getPolygonIntersection | [mlib.polygon.getLineIntersection](#mlibpolygongetlineintersection) |
| mlib.line.getLineIntersection | [mlib.line.getIntersection](#mliblinegetintersection) |
| mlib.segment.getCircleIntersection | [mlib.circle.getSegmentIntersection](#mlibcirclegetsegmentintersection) |
| milb.segment.getPolygonIntersection | [mlib.pollygon.getSegmentIntersection](#mlibpollygongetsegmentintersection) |
| mlib.segment.getLineIntersection | [mlib.line.getSegmentIntersection](#mliblinegetsegmentintersection) |
| mlib.segment.getSegmentIntersection | [mlib.segment.getIntersection](#mlibsegmentgetintersection) |
| milb.segment.isSegmentCompletelyInsideCircle | [mlib.circle.isSegmentCompletelyInside](#mlibcircleissegmentcompletelyinside) |
| mlib.segment.isSegmentCompletelyInsidePolygon | [mlib.polygon.isSegmentCompletelyInside](#mlibpolygonissegmentcompletelyinside) |
| mlib.circle.getPolygonIntersection | [mlib.polygon.getCircleIntersection](#mlibpolygongetcircleintersection) |
| mlib.circle.isCircleInsidePolygon | [mlib.polygon.isCircleInside](#mlibpolygoniscircleinside) |
| mlib.circle.isCircleCompletelyInsidePolygon | [mlib.polygon.isCircleCompletelyInside](#mlibpolygoniscirclecompletelyinside) |
| mlib.polygon.isCircleCompletelyOver | [mlib.circleisPolygonCompletelyInside](#mlibcircleispolygoncompletelyinside) |
## License
zlib license. See LICENSE.md