// noinspection JSUnusedGlobalSymbols
import {abs, ceiling, sqrt, exp, complex, sin, cos, pi} from '@backstrap/math';
import {Shape} from './Shape';
/**
* Class representing a factory for various simple 2D surfaces.
* @extends Coords
*/
export class Surface extends Shape {
/**
* @param {number} [w] - width
* @param {number} [h] - height
* @returns {Geometry[]}
*/
rect(w = 1, h = w) {
return this.surface((u, v) => [w*u, h*v, 0], [-0.5, 0.5, 1], [-0.5, 0.5, 1]);
}
/**
* @param {number} [w] - width
* @param {number} [h] - height
* @returns {Geometry[]}
*/
rightTriangle(w = 1, h = w) {
return this.surface((u, v) => [w*u*(1 - v), h*v, 0], [0, 1, 1], [0, 1, 1]);
}
/**
* Generate a regular polygon with N sides.
*
* @param {number} [n] - number of sides
* @param {number} [r] - radius of circumscribed circle
* @returns {Geometry[]}
*/
polygon(n = 5, r = 1) {
return this.surface(
(u, v) => u ? ((c => [r*c.re, r*c.im, 0])(exp(complex(0, v)))) : [0, 0, 0],
[0, 1, 1],
[0, 2*pi, n]
);
}
/**
* Generate a conic section, or a portion of one (annulus, cylinder, cone, etc.)
*
* @param {number} [r1] - inner radius
* @param {number} [r2] - outer radius
* @param {number} [h] - height
* @param {number} [angle = 2*pi] - included arc angle
* @returns {Geometry[]}
*/
conic(r1 = 0, r2 = 1, h = 1, angle = 2*pi) {
return this.surface(
(u, v) => [
(r1 + u*(r2 - r1))*cos(angle*v),
(r1 + u*(r2 - r1))*sin(angle*v),
(0.5 - u)*h
],
[0, 1, 1],
[0, 1, ceiling(abs(this.dv*angle/(2*pi)))]
);
}
/**
* Generate a disc, or a portion of one.
*
* @param {number} [r] - radius
* @param {number} [angle = 2*pi] - included arc angle
* @returns {Geometry[]}
*/
disc(r = 1, angle = 2*pi) {
return this.conic(0, r, 0, angle);
}
/**
* Generate a cylinder, or a portion of one.
*
* @param {number} [r] - radius
* @param {number} [h] - height
* @param {number} [angle = 2*pi] - included arc angle
* @returns {Geometry[]}
*/
cylinder(r = 1, h = 1, angle = 2*pi) {
return this.conic(r, r, h, angle);
}
/**
* Generate a hemisphere with cubic tesselation.
*
* @param {number} [r] - radius
* @param {boolean} [rev] - reverse orientation (normal pointing inward)
* @returns {Geometry[]}
*/
hemisphere(r = 1, rev = false) {
const dv = ceiling(this.dv/4);
const sRange = [-0.5, 0.5, dv];
const tRange = [rev ? 0.5 : 0, rev ? 0 : 0.5, dv];
const dist = (u, v) => r/sqrt(u*u + v*v + 0.25);
return [
this.surface((u, v) => (p => [ u*p, v*p, p/2])(dist(u, v)), sRange, rev ? [0.5, -0.5, dv] : sRange),
this.surface((u, v) => (p => [ p/2, u*p, v*p])(dist(u, v)), sRange, tRange),
this.surface((u, v) => (p => [ u*p, -p/2, v*p])(dist(u, v)), sRange, tRange),
this.surface((u, v) => (p => [-p/2, -u*p, v*p])(dist(u, v)), sRange, tRange),
this.surface((u, v) => (p => [-u*p, p/2, v*p])(dist(u, v)), sRange, tRange),
].flat();
}
/**
* Generate a sphere with lat/lon tesselation, or a portion of a spherical surface.
*
* @param {number} [r] - radius
* @param {number|function(number): number} [angle = 2*pi] - longitudinal segment size (0 to 2*pi)
* @param {number} [azimuth = pi] - latitudinal segment size (0 to pi)
* @param {number} [offset] - latitudinal offset (+/-(pi - azimuth)/2)
* @param {boolean} [rev] - reverse orientation (normal pointing inward)
* @returns {Geometry[]}
*/
sphereBand(r = 1, angle = 2*pi, azimuth = pi, offset = 0, rev = false) {
const getAngle = (typeof angle === 'function' ? angle : (() => angle));
return this.surface(
(u, v) => [
r*cos(getAngle(v)*u)*cos(azimuth*v + offset),
r*sin(getAngle(v)*u)*cos(azimuth*v + offset),
r*sin(azimuth*v + offset)
],
[-0.5, 0.5, 2*ceiling(abs(this.dv*getAngle(0)/(2*pi)))],
[rev ? 0.5 : -0.5, rev ? -0.5 : 0.5, 2*ceiling(abs(this.dv*azimuth/(2*pi)))]
);
}
}