+++ /dev/null
-/*
- * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
- * This project is released under Creative Commons Zero (CC0) license.
- *
- */
-
-package eu.svjatoslav.sixth.e3d.examples;
-
-import eu.svjatoslav.sixth.e3d.geometry.Point2D;
-import eu.svjatoslav.sixth.e3d.geometry.Point3D;
-import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
-import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.Graph;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Demo showing mathematical function graphs rendered in 3D.
- * Displays sine, cosine, tangent, and composite function graphs.
- */
-public class MathGraphsDemo {
-
- private static final double GRAPH_SCALE = 50d;
-
- /**
- * Creates a new MathGraphsDemo instance.
- */
- public MathGraphsDemo() {
- }
-
- /**
- * Creates a graph of the cosine function.
- * @param location the position of the graph in 3D space
- * @return a Graph component showing y = cos(x)
- */
- private static Graph getCosineGraph(final Point3D location) {
- final List<Point2D> data = new ArrayList<>();
- for (double x = 0; x < 20; x += 0.25) {
- final double y = Math.cos(x);
-
- final Point2D p = new Point2D(x, y);
- data.add(p);
- }
-
- return new Graph(GRAPH_SCALE, data, "Cosine", location);
- }
-
- /**
- * Creates a graph of y = sin(tan(x)).
- * @param location the position of the graph in 3D space
- * @return a Graph component showing the composite function
- */
- private static Graph getFormula1Graph(final Point3D location) {
- final List<Point2D> data = new ArrayList<>();
- for (double x = 0; x < 20; x += 0.25) {
- final double y = Math.sin(Math.tan(x));
-
- final Point2D p = new Point2D(x, y);
- data.add(p);
- }
-
- return new Graph(GRAPH_SCALE, data, "y = sin(tan(x))", location);
- }
-
- /**
- * Creates a graph of y = (10-x)^2 / 30.
- * @param location the position of the graph in 3D space
- * @return a Graph component showing the parabola
- */
- private static Graph getFormula2Graph(final Point3D location) {
- final List<Point2D> data = new ArrayList<>();
- for (double x = 0; x < 20; x += 0.25) {
- final double y = (Math.pow((10 - x), 2) / 30) - 2;
-
- final Point2D p = new Point2D(x, y);
- data.add(p);
- }
-
- return new Graph(GRAPH_SCALE, data, "y = ( (10-x)^2 ) / 30", location);
- }
-
- /**
- * Creates a graph of y = sin(x/2) + sin(x/1.26).
- * @param location the position of the graph in 3D space
- * @return a Graph component showing the composite sine wave
- */
- private static Graph getFormula3Graph(final Point3D location) {
- final List<Point2D> data = new ArrayList<>();
- for (double x = 0; x < 20; x += 0.25) {
- final double y = Math.sin(x / 2) + Math.sin(x / 1.26);
-
- final Point2D p = new Point2D(x, y);
- data.add(p);
- }
-
- return new Graph(GRAPH_SCALE, data, "y = sin(x/2) + sin(x/1.26)", location);
- }
-
- /**
- * Creates a graph of the sine function.
- * @param location the position of the graph in 3D space
- * @return a Graph component showing y = sin(x)
- */
- private static Graph getSineGraph(final Point3D location) {
- final List<Point2D> data = new ArrayList<>();
- for (double x = 0; x < 20; x += 0.25) {
- final double y = Math.sin(x);
-
- final Point2D p = new Point2D(x, y);
- data.add(p);
- }
-
- return new Graph(GRAPH_SCALE, data, "Sine", location);
- }
-
- /**
- * Creates a graph of the tangent function with clamped values.
- * @param location the position of the graph in 3D space
- * @return a Graph component showing y = tan(x) with clamped range
- */
- private static Graph getTangentGraph(final Point3D location) {
- final List<Point2D> data = new ArrayList<>();
- for (double x = 0; x < 20; x += 0.25) {
- double y = Math.tan(x);
-
- if (y > 2)
- y = 2;
- if (y < -2)
- y = -2;
-
- final Point2D p = new Point2D(x, y);
- data.add(p);
- }
-
- return new Graph(GRAPH_SCALE, data, "Tangent", location);
- }
-
- /**
- * Entry point for the math graphs demo.
- * @param args command line arguments (ignored)
- */
- public static void main(final String[] args) {
-
- final ViewFrame viewFrame = new ViewFrame();
- final ShapeCollection geometryCollection = viewFrame.getViewPanel()
- .getRootShapeCollection();
-
- addMathFormulas(geometryCollection);
-
- setCameraLocation(viewFrame);
-
- viewFrame.getViewPanel().ensureRenderThreadStarted();
- }
-
- /**
- * Adds all mathematical formula graphs to the scene.
- * @param geometryCollection the collection to add graphs to
- */
- private static void addMathFormulas(ShapeCollection geometryCollection) {
- int z = 1000;
- Point3D location = new Point3D(-600, -300, z);
- geometryCollection.addShape(getSineGraph(location));
-
- location = new Point3D(600, -300, z);
- geometryCollection.addShape(getFormula1Graph(location));
-
- location = new Point3D(-600, 0, z);
- geometryCollection.addShape(getCosineGraph(location));
-
- location = new Point3D(600, 0, z);
- geometryCollection.addShape(getFormula2Graph(location));
-
- location = new Point3D(-600, 300, z);
- geometryCollection.addShape(getTangentGraph(location));
-
- location = new Point3D(600, 300, z);
- geometryCollection.addShape(getFormula3Graph(location));
- }
-
- /**
- * Sets the camera to an initial viewing position.
- * @param viewFrame the view frame whose camera to configure
- */
- private static void setCameraLocation(ViewFrame viewFrame) {
- viewFrame.getViewPanel().getCamera().getTransform().setTranslation(new Point3D(0, 0, -500));
- }
-
-}
\ No newline at end of file
--- /dev/null
+/*
+ * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
+ * This project is released under Creative Commons Zero (CC0) license.
+ *
+ */
+
+package eu.svjatoslav.sixth.e3d.examples.graph_demo;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point2D;
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
+import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.Graph;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Demo showing mathematical function graphs rendered in 3D.
+ * Displays sine, cosine, tangent, and composite function graphs.
+ * Also includes a 3D surface graph showing z = (x² - y²) / 20 with
+ * intersecting planes and highlighted intersection curves.
+ */
+public class MathGraphsDemo {
+
+ private static final double GRAPH_SCALE = 50d;
+
+ /**
+ * Creates a new MathGraphsDemo instance.
+ */
+ public MathGraphsDemo() {
+ }
+
+ /**
+ * Creates a graph of the cosine function.
+ * @param location the position of the graph in 3D space
+ * @return a Graph component showing y = cos(x)
+ */
+ private static Graph getCosineGraph(final Point3D location) {
+ final List<Point2D> data = new ArrayList<>();
+ for (double x = 0; x < 20; x += 0.25) {
+ final double y = Math.cos(x);
+
+ final Point2D p = new Point2D(x, y);
+ data.add(p);
+ }
+
+ return new Graph(GRAPH_SCALE, data, "Cosine", location);
+ }
+
+ /**
+ * Creates a graph of y = sin(tan(x)).
+ * @param location the position of the graph in 3D space
+ * @return a Graph component showing the composite function
+ */
+ private static Graph getFormula1Graph(final Point3D location) {
+ final List<Point2D> data = new ArrayList<>();
+ for (double x = 0; x < 20; x += 0.25) {
+ final double y = Math.sin(Math.tan(x));
+
+ final Point2D p = new Point2D(x, y);
+ data.add(p);
+ }
+
+ return new Graph(GRAPH_SCALE, data, "y = sin(tan(x))", location);
+ }
+
+ /**
+ * Creates a graph of y = (10-x)^2 / 30.
+ * @param location the position of the graph in 3D space
+ * @return a Graph component showing the parabola
+ */
+ private static Graph getFormula2Graph(final Point3D location) {
+ final List<Point2D> data = new ArrayList<>();
+ for (double x = 0; x < 20; x += 0.25) {
+ final double y = (Math.pow((10 - x), 2) / 30) - 2;
+
+ final Point2D p = new Point2D(x, y);
+ data.add(p);
+ }
+
+ return new Graph(GRAPH_SCALE, data, "y = ( (10-x)^2 ) / 30", location);
+ }
+
+ /**
+ * Creates a graph of y = sin(x/2) + sin(x/1.26).
+ * @param location the position of the graph in 3D space
+ * @return a Graph component showing the composite sine wave
+ */
+ private static Graph getFormula3Graph(final Point3D location) {
+ final List<Point2D> data = new ArrayList<>();
+ for (double x = 0; x < 20; x += 0.25) {
+ final double y = Math.sin(x / 2) + Math.sin(x / 1.26);
+
+ final Point2D p = new Point2D(x, y);
+ data.add(p);
+ }
+
+ return new Graph(GRAPH_SCALE, data, "y = sin(x/2) + sin(x/1.26)", location);
+ }
+
+ /**
+ * Creates a graph of the sine function.
+ * @param location the position of the graph in 3D space
+ * @return a Graph component showing y = sin(x)
+ */
+ private static Graph getSineGraph(final Point3D location) {
+ final List<Point2D> data = new ArrayList<>();
+ for (double x = 0; x < 20; x += 0.25) {
+ final double y = Math.sin(x);
+
+ final Point2D p = new Point2D(x, y);
+ data.add(p);
+ }
+
+ return new Graph(GRAPH_SCALE, data, "Sine", location);
+ }
+
+ /**
+ * Creates a graph of the tangent function with clamped values.
+ * @param location the position of the graph in 3D space
+ * @return a Graph component showing y = tan(x) with clamped range
+ */
+ private static Graph getTangentGraph(final Point3D location) {
+ final List<Point2D> data = new ArrayList<>();
+ for (double x = 0; x < 20; x += 0.25) {
+ double y = Math.tan(x);
+
+ if (y > 2)
+ y = 2;
+ if (y < -2)
+ y = -2;
+
+ final Point2D p = new Point2D(x, y);
+ data.add(p);
+ }
+
+ return new Graph(GRAPH_SCALE, data, "Tangent", location);
+ }
+
+ /**
+ * Entry point for the math graphs demo.
+ * @param args command line arguments (ignored)
+ */
+ public static void main(final String[] args) {
+
+ final ViewFrame viewFrame = new ViewFrame();
+ final ShapeCollection geometryCollection = viewFrame.getViewPanel()
+ .getRootShapeCollection();
+
+ addMathFormulas(geometryCollection);
+ addSurfaceGraph(geometryCollection);
+
+ setCameraLocation(viewFrame);
+
+ viewFrame.getViewPanel().ensureRenderThreadStarted();
+ }
+
+ /**
+ * Adds all mathematical formula graphs to the scene.
+ * @param geometryCollection the collection to add graphs to
+ */
+ private static void addMathFormulas(ShapeCollection geometryCollection) {
+ int z = 1000;
+ Point3D location = new Point3D(-600, -300, z);
+ geometryCollection.addShape(getSineGraph(location));
+
+ location = new Point3D(600, -300, z);
+ geometryCollection.addShape(getFormula1Graph(location));
+
+ location = new Point3D(-600, 0, z);
+ geometryCollection.addShape(getCosineGraph(location));
+
+ location = new Point3D(600, 0, z);
+ geometryCollection.addShape(getFormula2Graph(location));
+
+ location = new Point3D(-600, 300, z);
+ geometryCollection.addShape(getTangentGraph(location));
+
+ location = new Point3D(600, 300, z);
+ geometryCollection.addShape(getFormula3Graph(location));
+ }
+
+ private static void addSurfaceGraph(ShapeCollection geometryCollection) {
+ final double range = 10;
+ final double step = 0.5;
+ final double scale = 30;
+
+ final SurfaceGraph3D.MathFunction3D function = (x, y) -> (x * x - y * y) / 20;
+
+ SurfaceGraph3D surface = new SurfaceGraph3D(
+ -range, range, step,
+ -range, range, step,
+ function,
+ new Color(150, 150, 150, 180),
+ Color.WHITE,
+ scale,
+ new Point3D(0, 0, 0)
+ );
+
+ surface.addYIntersectionCurve(4, function, new Color(255, 255, 0, 220), 1.2);
+ surface.addXIntersectionCurve(-4, function, new Color(255, 120, 0, 220), 1.2);
+
+ geometryCollection.addShape(surface);
+ }
+
+ /**
+ * Sets the camera to an initial viewing position.
+ * @param viewFrame the view frame whose camera to configure
+ */
+ private static void setCameraLocation(ViewFrame viewFrame) {
+ viewFrame.getViewPanel().getCamera().getTransform().setTranslation(new Point3D(0, 0, -500));
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
+ * This project is released under Creative Commons Zero (CC0) license.
+ */
+package eu.svjatoslav.sixth.e3d.examples.graph_demo;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.line.Line;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.solidpolygon.SolidPolygon;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape;
+
+/**
+ * A 3D surface graph that visualizes mathematical functions of the form z = f(x, y).
+ *
+ * <p>The surface is rendered as a grid of quadrilaterals (split into triangles) with
+ * optional wireframe overlay. The surface color can be customized, and the wireframe
+ * lines are drawn in a contrasting color.</p>
+ *
+ * <p><b>Usage example:</b></p>
+ * <pre>{@code
+ * // Create a saddle surface: z = x^2 - y^2
+ * SurfaceGraph3D saddle = new SurfaceGraph3D(
+ * -5, 5, 0.5, // x range and step
+ * -5, 5, 0.5, // y range and step
+ * (x, y) -> x * x - y * y, // function z = f(x, y)
+ * new Color(180, 180, 180, 200), // gray semi-transparent surface
+ * new Color(255, 255, 255), // white grid lines
+ * new Point3D(0, 0, 0) // position in 3D space
+ * );
+ * shapeCollection.addShape(saddle);
+ * }</pre>
+ *
+ * @see AbstractCompositeShape
+ * @see SolidPolygon
+ * @see Line
+ */
+public class SurfaceGraph3D extends AbstractCompositeShape {
+
+ private final double xMin;
+ private final double xMax;
+ private final double xStep;
+ private final double yMin;
+ private final double yMax;
+ private final double yStep;
+ private final double scale;
+ private final Color surfaceColor;
+ private final Color gridColor;
+ private final double lineWidth;
+
+ /**
+ * Creates a 3D surface graph at the specified location.
+ *
+ * @param xMin minimum X value of the domain
+ * @param xMax maximum X value of the domain
+ * @param xStep step size between grid points along X axis
+ * @param yMin minimum Y value of the domain
+ * @param yMax maximum Y value of the domain
+ * @param yStep step size between grid points along Y axis
+ * @param function the mathematical function z = f(x, y) to visualize
+ * @param surfaceColor color of the surface polygons (use semi-transparent for see-through effect)
+ * @param gridColor color of the wireframe grid lines
+ * @param lineWidth width of grid lines in world units
+ * @param scale scale factor applied to all generated vertices
+ * @param location the 3D position of the graph's origin
+ */
+ public SurfaceGraph3D(final double xMin, final double xMax, final double xStep,
+ final double yMin, final double yMax, final double yStep,
+ final MathFunction3D function,
+ final Color surfaceColor, final Color gridColor,
+ final double lineWidth, final double scale, final Point3D location) {
+ super(location);
+
+ this.xMin = xMin;
+ this.xMax = xMax;
+ this.yMin = yMin;
+ this.yMax = yMax;
+ this.xStep = xStep;
+ this.yStep = yStep;
+ this.scale = scale;
+ this.surfaceColor = surfaceColor;
+ this.gridColor = gridColor;
+ this.lineWidth = lineWidth;
+
+ generateSurface(function);
+ }
+
+ public SurfaceGraph3D(final double xMin, final double xMax, final double xStep,
+ final double yMin, final double yMax, final double yStep,
+ final MathFunction3D function,
+ final Color surfaceColor, final Color gridColor,
+ final double scale, final Point3D location) {
+ this(xMin, xMax, xStep, yMin, yMax, yStep, function, surfaceColor, gridColor, 0.1, scale, location);
+ }
+
+ private void generateSurface(final MathFunction3D function) {
+ final int xCount = (int) ((xMax - xMin) / xStep) + 1;
+ final int yCount = (int) ((yMax - yMin) / yStep) + 1;
+
+ final Point3D[][] vertices = new Point3D[xCount][yCount];
+
+ for (int i = 0; i < xCount; i++) {
+ for (int j = 0; j < yCount; j++) {
+ final double x = xMin + i * xStep;
+ final double y = yMin + j * yStep;
+ final double z = function.apply(x, y);
+ vertices[i][j] = new Point3D(x * scale, -z * scale, y * scale);
+ }
+ }
+
+ for (int i = 0; i < xCount - 1; i++) {
+ for (int j = 0; j < yCount - 1; j++) {
+ final Point3D p1 = vertices[i][j];
+ final Point3D p2 = vertices[i + 1][j];
+ final Point3D p3 = vertices[i][j + 1];
+ final Point3D p4 = vertices[i + 1][j + 1];
+
+ addQuad(p1, p2, p3, p4);
+ addGridLines(p1, p2, p3, p4);
+ }
+ }
+ }
+
+ private void addQuad(final Point3D p1, final Point3D p2, final Point3D p3, final Point3D p4) {
+ final SolidPolygon poly1 = new SolidPolygon(p1, p2, p3, surfaceColor);
+ poly1.setBackfaceCulling(false);
+ addShape(poly1);
+
+ final SolidPolygon poly2 = new SolidPolygon(p2, p4, p3, surfaceColor);
+ poly2.setBackfaceCulling(false);
+ addShape(poly2);
+ }
+
+ private void addGridLines(final Point3D p1, final Point3D p2, final Point3D p3, final Point3D p4) {
+ addShape(new Line(p1, p2, gridColor, lineWidth));
+ addShape(new Line(p2, p4, gridColor, lineWidth));
+ addShape(new Line(p3, p4, gridColor, lineWidth));
+ addShape(new Line(p1, p3, gridColor, lineWidth));
+ }
+
+ /**
+ * Adds a curve highlighting the intersection of the surface with a vertical plane at constant X.
+ *
+ * @param xValue the X coordinate of the intersecting plane
+ * @param function the mathematical function z = f(x, y)
+ * @param color the color of the intersection curve
+ * @param width the line width
+ */
+ public void addXIntersectionCurve(final double xValue, final MathFunction3D function,
+ final Color color, final double width) {
+ Point3D prevPoint = null;
+ for (double y = yMin; y <= yMax; y += 0.15) {
+ final double z = function.apply(xValue, y);
+ final Point3D currentPoint = new Point3D(xValue * scale, -z * scale, y * scale);
+ if (prevPoint != null) {
+ addShape(new Line(prevPoint, currentPoint, color, width));
+ }
+ prevPoint = currentPoint;
+ }
+ }
+
+ /**
+ * Adds a curve highlighting the intersection of the surface with a vertical plane at constant Y.
+ *
+ * @param yValue the Y coordinate of the intersecting plane
+ * @param function the mathematical function z = f(x, y)
+ * @param color the color of the intersection curve
+ * @param width the line width
+ */
+ public void addYIntersectionCurve(final double yValue, final MathFunction3D function,
+ final Color color, final double width) {
+ Point3D prevPoint = null;
+ for (double x = xMin; x <= xMax; x += 0.15) {
+ final double z = function.apply(x, yValue);
+ final Point3D currentPoint = new Point3D(x * scale, -z * scale, yValue * scale);
+ if (prevPoint != null) {
+ addShape(new Line(prevPoint, currentPoint, color, width));
+ }
+ prevPoint = currentPoint;
+ }
+ }
+
+ /**
+ * Functional interface for 3D mathematical functions of the form z = f(x, y).
+ */
+ @FunctionalInterface
+ public interface MathFunction3D {
+ /**
+ * Computes the Z value for given X and Y coordinates.
+ *
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ * @return the Z value (height) at the given (x, y) position
+ */
+ double apply(double x, double y);
+ }
+}
package eu.svjatoslav.sixth.e3d.examples.launcher;
import eu.svjatoslav.sixth.e3d.examples.SineHeightmap;
-import eu.svjatoslav.sixth.e3d.examples.MathGraphsDemo;
+import eu.svjatoslav.sixth.e3d.examples.graph_demo.MathGraphsDemo;
import eu.svjatoslav.sixth.e3d.examples.MinimalExample;
import eu.svjatoslav.sixth.e3d.examples.OctreeDemo;
import eu.svjatoslav.sixth.e3d.examples.RandomPolygonsDemo;