Add some comments in RasterGeometry.h
This commit is contained in:
parent
26a111a704
commit
ebf21c0e0e
@ -1,16 +1,18 @@
|
||||
#include "Geometry.h"
|
||||
|
||||
// Assuming abs(dw) <= dz
|
||||
// Draw a line from the origin on the ZW plane, assuming abs(dw) <= dz
|
||||
template<bool Ortho, typename F>
|
||||
void rasterizeLineZW(int dz, int dw, F f)
|
||||
{
|
||||
const int incW = dw >= 0 ? 1 : -1;
|
||||
int z = 0, w = 0, err = 0;
|
||||
// err / (2 * dz) is the fractional error in w
|
||||
while (z <= dz)
|
||||
int w = 0, err = 0;
|
||||
for (int z = 0; z <= dz; z++)
|
||||
{
|
||||
f(z, w);
|
||||
|
||||
// err / (2 * dz) is the difference between the integer w and the
|
||||
// (potentially non-integer) value z * dw / dz that would like w to be.
|
||||
// When the difference becomes too large, we can increment w.
|
||||
err += 2 * dw * incW;
|
||||
if (err >= dz)
|
||||
{
|
||||
@ -19,23 +21,24 @@ void rasterizeLineZW(int dz, int dw, F f)
|
||||
if (Ortho && z < dz)
|
||||
f(z, w);
|
||||
}
|
||||
|
||||
z++;
|
||||
}
|
||||
}
|
||||
|
||||
// Ortho makes the resulting line orthogonally connected
|
||||
// Call f for every point on the rasterization of a line between p1 and p2.
|
||||
// Ortho makes the resulting line orthogonally connected.
|
||||
template<bool Ortho, typename F>
|
||||
void RasterizeLine(Vec2<int> p1, Vec2<int> p2, F f)
|
||||
{
|
||||
if(std::abs(p1.X - p2.X) >= std::abs(p1.Y - p2.Y))
|
||||
{
|
||||
// If it's more wide than tall, map Z to X and W to Y
|
||||
auto source = p1.X < p2.X ? p1 : p2;
|
||||
auto delta = p1.X < p2.X ? p2 - p1 : p1 - p2;
|
||||
rasterizeLineZW<Ortho>(delta.X, delta.Y, [source, f](int z, int w) { f(source + Vec2<int>(z, w)); });
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's more tall than wide, map Z to Y and W to X
|
||||
auto source = p1.Y < p2.Y ? p1 : p2;
|
||||
auto delta = p1.Y < p2.Y ? p2 - p1 : p1 - p2;
|
||||
rasterizeLineZW<Ortho>(delta.Y, delta.X, [source, f](int z, int w) { f(source + Vec2<int>(w, z)); });
|
||||
@ -45,20 +48,35 @@ void RasterizeLine(Vec2<int> p1, Vec2<int> p2, F f)
|
||||
template<typename F>
|
||||
void rasterizeEllipseQuadrant(Vec2<float> radiusSquared, F f)
|
||||
{
|
||||
// An ellipse is a region of points (x, y) such that
|
||||
// (x / rx)^2 + (y / ry)^2 <= 1, which can be rewritten as
|
||||
// x^2 * ry^2 + y^2 * rx^2 <= ry^2 * rx^2,
|
||||
// except, if rx == 0, then an additional constraint abs(y) <= ry must be
|
||||
// added, and same for ry.
|
||||
// The code below ensures 0 <= x <= rx and 0 <= y <= ry + 1.
|
||||
// A false positive for y > ry can only happen if rx == 0 and does not
|
||||
// affect the outcome
|
||||
auto inEllipse = [=](int x, int y)
|
||||
{
|
||||
return y * y * radiusSquared.X + x * x * radiusSquared.Y <= radiusSquared.X * radiusSquared.Y;
|
||||
};
|
||||
// Focusing on the bottom right quadrant, in every row we find the range of
|
||||
// points inside the ellipse, and within those, the range of points on the
|
||||
// boundary.
|
||||
int x = int(std::floor(std::sqrt(radiusSquared.X)));
|
||||
int maxY = int(std::floor(std::sqrt(radiusSquared.Y)));
|
||||
for (int y = 0; y <= maxY; y++)
|
||||
{
|
||||
// At the start of each iteration, (x, y) is on the boundary,
|
||||
// i.e. the range of points inside the ellipse is [0, x]
|
||||
if (inEllipse(x, y + 1))
|
||||
{
|
||||
// If the point below is inside, x is the only boundary point
|
||||
f(x, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, all points whose below point is outside -- are on the boundary
|
||||
int xStart = x;
|
||||
do
|
||||
{
|
||||
@ -69,6 +87,13 @@ void rasterizeEllipseQuadrant(Vec2<float> radiusSquared, F f)
|
||||
}
|
||||
}
|
||||
|
||||
// Call f for every point on the rasterized boundary of the ellipse with the
|
||||
// indicated radius.
|
||||
// In some situations we may want the radius to be the square root of an
|
||||
// integer, so passing the radius squared allows for exact calculation.
|
||||
// In some situations we may want the radius to be a half-integer, and floating
|
||||
// point arithmetic is still exact for half-integers (really, 1/16ths), which is
|
||||
// why we pass this as a float.
|
||||
template<typename F>
|
||||
void RasterizeEllipsePoints(Vec2<float> radiusSquared, F f)
|
||||
{
|
||||
@ -84,6 +109,7 @@ void RasterizeEllipsePoints(Vec2<float> radiusSquared, F f)
|
||||
});
|
||||
}
|
||||
|
||||
// Call f for every point inside the ellipse with the indicated radius.
|
||||
template<typename F>
|
||||
void RasterizeEllipseRows(Vec2<float> radiusSquared, F f)
|
||||
{
|
||||
|
Reference in New Issue
Block a user