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 public boolean equals(final Object o) {
54 if (o == null) return false;
56 return o instanceof LineInterpolator && compareTo((LineInterpolator) o) == 0;
60 public int compareTo(final LineInterpolator o) {
61 if (absoluteHeight < o.absoluteHeight)
63 if (absoluteHeight > o.absoluteHeight)
66 return Integer.compare(o.width, width);
71 public int hashCode() {
73 result = 31 * result + absoluteHeight;
78 * Tests whether the given y coordinate falls within the vertical span of this edge.
80 * @param y the scanline y coordinate to test
81 * @return {@code true} if {@code y} is between the y coordinates of the two endpoints (inclusive)
83 public boolean containsY(final int y) {
95 * Computes the interpolated x coordinate for the given scanline y value.
97 * <p>If the edge is horizontal (height is zero), returns the average of the
98 * two endpoint x coordinates.</p>
100 * @param y the scanline y coordinate
101 * @return the interpolated x coordinate on this edge at the given y
103 public int getX(final int y) {
106 return (int) (p2.x + p1.x) / 2;
108 return (int) (p1.x + ((width * (y - p1.y)) / height));
112 * Sets the two endpoints of this edge and precomputes the width, height, and absolute height.
114 * @param p1 the first endpoint
115 * @param p2 the second endpoint
117 public void setPoints(final Point2D p1, final Point2D p2) {
120 height = (int) (p2.y - p1.y);
121 width = (int) (p2.x - p1.x);
123 absoluteHeight = Math.abs(height);