Files
cell/prosperon/geometry.cm

249 lines
8.2 KiB
Plaintext

var geometry = this
geometry[cell.DOC] = `
A collection of geometry-related functions for circles, spheres, boxes, polygons,
and rectangle utilities. Some functionality is implemented in C and exposed here.
`
var math = use('math')
geometry.box = {}
geometry.box[cell.DOC] = `
An object for box-related operations. Overridden later by a function definition, so
its direct usage is overshadowed. Contains:
- points(ll, ur): Return an array of four 2D points for a box from ll (lower-left) to ur (upper-right).
`
geometry.box.points = function (ll, ur) {
return [ll, ll.add([ur.x - ll.x, 0]), ur, ll.add([0, ur.y - ll.y])]
}
geometry.box.points[cell.DOC] = `
:param ll: Lower-left coordinate as a 2D vector (x,y).
:param ur: Upper-right coordinate as a 2D vector (x,y).
:return: An array of four points forming the corners of the box in order [ll, lower-right, ur, upper-left].
Compute the four corners of a box given lower-left and upper-right corners.
`
geometry.sphere = {}
geometry.sphere[cell.DOC] = `
Sphere-related geometry functions:
- volume(r): Return the volume of a sphere with radius r.
- random(r, theta, phi): Return a random point on or inside a sphere.
`
geometry.circle = {}
geometry.circle[cell.DOC] = `
Circle-related geometry functions:
- area(r): Return the area of a circle with radius r.
- random(r, theta): Return a random 2D point on a circle; uses sphere.random internally and extracts x,z.
`
geometry.sphere.volume = function (r) {
return (Math.pi * r * r * r * 4) / 3
}
geometry.sphere.volume[cell.DOC] = `
:param r: The sphere radius.
:return: The volume of the sphere, calculated as (4/3) * pi * r^3.
`
geometry.sphere.random = function (r, theta = [0, 1], phi = [-0.5, 0.5]) {
if (typeof r == "number") r = [r, r]
if (typeof theta == "number") theta = [theta, theta]
if (typeof phi == "number") phi = [phi, phi]
var ra = Math.random_range(r[0], r[1])
var ta = Math.turn2rad(Math.random_range(theta[0], theta[1]))
var pa = Math.turn2rad(Math.random_range(phi[0], phi[1]))
return [ra * Math.sin(ta) * Math.cos(pa), ra * Math.sin(ta) * Math.sin(pa), ra * Math.cos(ta)]
}
geometry.sphere.random[cell.DOC] = `
:param r: A single number (radius) or a 2-element array [minRadius, maxRadius].
:param theta: A single number or 2-element array defining the range in turns for the theta angle, default [0,1].
:param phi: A single number or 2-element array defining the range in turns for the phi angle, default [-0.5,0.5].
:return: A 3D point (x,y,z) randomly placed within a sphere.
Generate a random point inside a sphere of variable radius, distributing angles in the specified ranges.
`
geometry.circle.area = function (r) {
return Math.pi * r * r
}
geometry.circle.area[cell.DOC] = `
:param r: Radius of the circle.
:return: The area, pi * r^2.
`
geometry.circle.random = function (r, theta) {
return geometry.sphere.random(r, theta).xz
}
geometry.circle.random[cell.DOC] = `
:param r: A radius or [minRadius, maxRadius].
:param theta: Angle range in turns (single number or [min,max]).
:return: A 2D point (x,z) in the circle, using the sphere random generator and ignoring y.
`
geometry.box = function (w, h) {
w /= 2
h /= 2
var points = [
[w, h],
[-w, h],
[-w, -h],
[w, -h],
]
return points
}
geometry.box[cell.DOC] = `
:param w: The width of the box.
:param h: The height of the box.
:return: An array of four 2D points representing the corners of a rectangle centered at [0,0].
Construct a box centered at the origin with the given width and height. This overrides the box object above.
`
geometry.ngon = function (radius, n) {
return geometry.arc(radius, 360, n)
}
geometry.ngon[cell.DOC] = `
:param radius: The radius of the n-gon from center to each vertex.
:param n: Number of sides/vertices.
:return: An array of 2D points forming a regular n-gon.
Generates a regular n-gon by calling geometry.arc with full 360 degrees.
`
geometry.arc = function (radius, angle, n, start = 0) {
start = Math.deg2rad(start)
if (angle >= 360) angle = 360
if (n <= 1) return []
var points = []
angle = Math.deg2rad(angle)
var arclen = angle / n
for (var i = 0; i < n; i++) points.push(math.rotate([radius, 0], start + arclen * i))
return points
}
geometry.arc[cell.DOC] = `
:param radius: The distance from center to the arc points.
:param angle: The total angle (in degrees) over which points are generated, capped at 360.
:param n: Number of segments (if <=1, empty array is returned).
:param start: Starting angle (in degrees), default 0.
:return: An array of 2D points along the arc.
Generate an arc (or partial circle) of n points, each angle spread equally over 'angle' degrees from 'start'.
`
geometry.circle.points = function (radius, n) {
if (n <= 1) return []
return geometry.arc(radius, 360, n)
}
geometry.circle.points[cell.DOC] = `
:param radius: The circle's radius.
:param n: Number of points around the circle.
:return: An array of 2D points equally spaced around a full 360-degree circle.
Shortcut for geometry.arc(radius, 360, n).
`
geometry.corners2points = function (ll, ur) {
return [ll, ll.add([ur.x, 0]), ur, ll.add([0, ur.y])]
}
geometry.corners2points[cell.DOC] = `
:param ll: Lower-left 2D coordinate.
:param ur: Upper-right 2D coordinate (relative offset in x,y).
:return: A four-point array of corners [ll, lower-right, upper-right, upper-left].
Similar to box.points, but calculates differently.
`
geometry.sortpointsccw = function (points) {
var cm = points2cm(points)
var cmpoints = points.map(function (x) { return x.sub(cm) })
var ccw = cmpoints.sort(function (a, b) {
var aatan = Math.atan2(a.y, a.x)
var batan = Math.atan2(b.y, b.x)
return aatan - batan
})
return ccw.map(function (x) { return x.add(cm) })
}
geometry.sortpointsccw[cell.DOC] = `
:param points: An array of 2D points.
:return: A new array of the same points, sorted counterclockwise around their centroid.
Sort an array of points in CCW order based on their angles from the centroid.
`
function points2cm(pts) {
var x = 0
var y = 0
var n = pts.length
pts.forEach(function (p) {
x += p[0]
y += p[1]
})
return [x / n, y / n]
}
geometry.points2cm = function(points) {
var x = 0
var y = 0
var n = points.length
points.forEach(function (p) {
x += p[0]
y += p[1]
})
return [x / n, y / n]
}
geometry.points2cm[cell.DOC] = `
:param points: An array of 2D points.
:return: The centroid (average x,y) of the given points.
`
geometry.rect_intersection[cell.DOC] = `
:param a: The first rectangle as {x, y, w, h}.
:param b: The second rectangle as {x, y, w, h}.
:return: A rectangle that is the intersection of the two. May have zero width/height if no overlap.
Return the intersection of two rectangles. The result may be empty if no intersection.
`
geometry.rect_intersects[cell.DOC] = `
:param a: Rectangle {x,y,w,h}.
:param b: Rectangle {x,y,w,h}.
:return: A boolean indicating whether the two rectangles overlap.
`
geometry.rect_expand[cell.DOC] = `
:param a: Rectangle {x,y,w,h}.
:param b: Rectangle {x,y,w,h}.
:return: A new rectangle that covers the bounds of both input rectangles.
Merge or combine two rectangles, returning their bounding rectangle.
`
geometry.rect_inside[cell.DOC] = `
:param inner: A rectangle to test.
:param outer: A rectangle that may contain 'inner'.
:return: True if 'inner' is completely inside 'outer', otherwise false.
`
geometry.rect_random[cell.DOC] = `
:param rect: A rectangle {x,y,w,h}.
:return: A random point within the rectangle (uniform distribution).
`
geometry.cwh2rect[cell.DOC] = `
:param center: A 2D point [cx, cy].
:param wh: A 2D size [width, height].
:return: A rectangle {x, y, w, h} with x,y set to center and w,h set to the given size.
Helper: convert a center point and width/height vector to a rect object.
`
geometry.rect_point_inside[cell.DOC] = `
:param rect: A rectangle {x,y,w,h}.
:param point: A 2D point [px, py].
:return: True if the point lies inside the rectangle, otherwise false.
`
geometry.rect_pos[cell.DOC] = `
:param rect: A rectangle {x,y,w,h}.
:return: A 2D vector [x,y] giving the rectangle's position.
`
geometry.rect_move[cell.DOC] = `
:param rect: A rectangle {x,y,w,h}.
:param offset: A 2D vector to add to the rectangle's position.
:return: A new rectangle with updated x,y offset.
`
return geometry