2 * Sixth 3D engine. Author: Svjatoslav Agejenko.
3 * This project is released under Creative Commons Zero (CC0) license.
5 package eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.solidpolygon;
7 import eu.svjatoslav.sixth.e3d.geometry.Point2D;
10 * Interpolates the x coordinate along a 2D line edge for scanline-based polygon rasterization.
12 * <p>{@code LineInterpolator} represents one edge of a polygon in screen space, defined by
13 * two {@link Point2D} endpoints. Given a scanline y coordinate, it computes the corresponding
14 * x coordinate via linear interpolation. This is a core building block for the solid polygon
15 * rasterizer, which fills triangles by sweeping horizontal scanlines and using two
16 * {@code LineInterpolator} instances to find the left and right x boundaries at each y level.</p>
18 * <p>Instances are {@link Comparable}, sorted by absolute height (tallest first) and then
19 * by width. This ordering is used during rasterization to select the primary (longest) edge
20 * of the triangle for the outer scanline loop.</p>
22 * @see eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.solidpolygon.SolidPolygon
25 public class LineInterpolator implements Comparable<LineInterpolator> {
28 * The first endpoint of this edge.
33 * The second endpoint of this edge.
38 * The vertical span (p2.y - p1.y), which may be negative.
43 * The horizontal span (p2.x - p1.x), which may be negative.
48 * The absolute value of the vertical span, used for sorting.
50 private int absoluteHeight;
53 * Creates a new line interpolator with uninitialized endpoints.
55 public LineInterpolator() {
59 public boolean equals(final Object o) {
60 if (o == null) return false;
62 return o instanceof LineInterpolator && compareTo((LineInterpolator) o) == 0;
66 public int compareTo(final LineInterpolator o) {
67 if (absoluteHeight < o.absoluteHeight)
69 if (absoluteHeight > o.absoluteHeight)
72 return Integer.compare(o.width, width);
77 public int hashCode() {
79 result = 31 * result + absoluteHeight;
84 * Tests whether the given y coordinate falls within the vertical span of this edge.
86 * @param y the scanline y coordinate to test
87 * @return {@code true} if {@code y} is between the y coordinates of the two endpoints (inclusive)
89 public boolean containsY(final int y) {
101 * Computes the interpolated x coordinate for the given scanline y value.
103 * <p>If the edge is horizontal (height is zero), returns the average of the
104 * two endpoint x coordinates.</p>
106 * @param y the scanline y coordinate
107 * @return the interpolated x coordinate on this edge at the given y
109 public int getX(final int y) {
112 return (int) (p2.x + p1.x) / 2;
114 return (int) (p1.x + ((width * (y - p1.y)) / height));
118 * Sets the two endpoints of this edge and precomputes the width, height, and absolute height.
120 * @param p1 the first endpoint
121 * @param p2 the second endpoint
123 public void setPoints(final Point2D p1, final Point2D p2) {
126 height = (int) (p2.y - p1.y);
127 width = (int) (p2.x - p1.x);
129 absoluteHeight = Math.abs(height);