Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package org.example.type;
- import com.googlecode.lanterna.*;
- import com.googlecode.lanterna.TextColor.RGB;
- import com.googlecode.lanterna.screen.*;
- import com.googlecode.lanterna.terminal.*;
- import java.io.IOException;
- import java.util.*;
- import lombok.AllArgsConstructor;
- import lombok.Value;
- public class QuasarSimulation {
- private Screen screen;
- private final List<Point> quasarPoints = new ArrayList<>();
- private double[][] depthBuffer;
- public static void main(String[] args) throws IOException, InterruptedException {
- new QuasarSimulation().drawQuasar();
- }
- public void drawQuasar() throws IOException, InterruptedException {
- screen = new TerminalScreen(
- new DefaultTerminalFactory().setInitialTerminalSize(new TerminalSize(80, 30))
- .createTerminal());
- screen.startScreen();
- depthBuffer = new double[screen.getTerminalSize().getColumns()][screen.getTerminalSize()
- .getRows()];
- initializeQuasarPoints();
- int centerX = screen.getTerminalSize().getColumns() / 2;
- int centerY = screen.getTerminalSize().getRows() / 2;
- double rotationAngle = Math.toRadians(-0.1);
- while (true) {
- for (double[] row : depthBuffer) {
- Arrays.fill(row, Double.MAX_VALUE);
- }
- screen.clear();
- quasarPoints.replaceAll(p -> rotate(p, rotationAngle, centerX, centerY));
- drawDisk();
- screen.refresh();
- Thread.sleep(25);
- }
- }
- private void initializeQuasarPoints() {
- int centerX = screen.getTerminalSize().getColumns() / 2;
- int centerY = screen.getTerminalSize().getRows() / 2;
- Random random = new Random();
- quasarPoints.add(new Point(centerX, centerY, 0));
- for (int arm = 0; arm < 4; arm++) {
- for (double theta = 0; theta < 4 * Math.PI; theta += 0.01) {
- double r = 0.1 * Math.exp(0.5 * theta);
- double x = centerX + (r * Math.cos(theta + arm * Math.PI / 2));
- double y = centerY + (r * Math.sin(theta + arm * Math.PI / 2));
- int z = random.nextInt(6) - 3;
- quasarPoints.add(new Point(x, y, z));
- for (int i = 0; i < random.nextInt(2); i++) {
- quasarPoints.add(new Point(x + random.nextInt(12) - 6, y + random.nextInt(12) - 6, z));
- }
- }
- }
- for (int i = 1; i <= 200; i++) {
- double r = i * 0.05;
- int z = i / 2;
- for (double angle = 0; angle < 2 * Math.PI; angle += 0.1) {
- int x = centerX + (int) (r * Math.cos(angle));
- int y = centerY + (int) (r * Math.sin(angle));
- TextCharacter ch = new TextCharacter('*', TextColor.Factory.fromString("#FFFFFF"),
- TextColor.ANSI.BLACK);
- quasarPoints.addAll(Arrays.asList(new Point(x, y, z, Optional.of(ch)),
- new Point(x, y, -z, Optional.of(ch))));
- }
- }
- }
- double i = 0;
- private void drawDisk() {
- int centerX = screen.getTerminalSize().getColumns() / 2;
- int centerY = screen.getTerminalSize().getRows() / 2;
- int depth = 100;
- double viewAngleX = Math.toRadians(-50 + (i += 0.3));
- double viewAngleY = Math.toRadians(4);
- for (Point point : quasarPoints) {
- Point adjustedPoint = applyViewingAngle(point, viewAngleX, viewAngleY, centerX, centerY);
- double projectedX =
- (depth * (adjustedPoint.getX() - centerX)) / (adjustedPoint.getZ() + depth) + centerX;
- double projectedY =
- (depth * (adjustedPoint.getY() - centerY)) / (adjustedPoint.getZ() + depth) + centerY;
- TextCharacter textCharacter = adjustedPoint.getCharacter()
- .orElseGet(() -> getQuasarCharacter(point, centerX, centerY));
- int intX = (int) projectedX;
- int intY = (int) projectedY;
- if (intX >= 0 && intX < depthBuffer.length && intY >= 0 && intY < depthBuffer[intX].length
- && point.getZ() < depthBuffer[intX][intY]) {
- depthBuffer[intX][intY] = point.getZ();
- screen.setCharacter(intX, intY, textCharacter);
- }
- }
- }
- private Point applyViewingAngle(Point point, double angleX, double angleY, int centerX,
- int centerY) {
- // Translate to the origin
- double translatedX = point.getX() - centerX;
- double translatedY = point.getY() - centerY;
- double z = point.getZ();
- // Apply rotation around X-axis
- double adjustedY = translatedY * Math.cos(angleX) - z * Math.sin(angleX);
- double adjustedZ = translatedY * Math.sin(angleX) + z * Math.cos(angleX);
- // Apply rotation around Y-axis
- double adjustedX = translatedX * Math.cos(angleY) + adjustedZ * Math.sin(angleY);
- adjustedZ = -translatedX * Math.sin(angleY) + adjustedZ * Math.cos(angleY);
- // Translate back
- adjustedX += centerX;
- adjustedY += centerY;
- return new Point(adjustedX, adjustedY, adjustedZ, point.getCharacter());
- }
- private Point rotate(Point point, double angle, int centerX, int centerY) {
- double x =
- (point.getX() - centerX) * Math.cos(angle) - (point.getY() - centerY) * Math.sin(angle)
- + centerX;
- double y =
- (point.getX() - centerX) * Math.sin(angle) + (point.getY() - centerY) * Math.cos(angle)
- + centerY;
- return new Point(x, y, point.getZ(), point.getCharacter());
- }
- // Linear interpolation function
- private TextColor lerpColor(String startColor, String endColor, double t) {
- TextColor start = TextColor.Factory.fromString(startColor);
- TextColor end = TextColor.Factory.fromString(endColor);
- int r = (int) (start.getRed() + t * (end.getRed() - start.getRed()));
- int g = (int) (start.getGreen() + t * (end.getGreen() - start.getGreen()));
- int b = (int) (start.getBlue() + t * (end.getBlue() - start.getBlue()));
- return new RGB(r, g, b);
- }
- private TextCharacter getQuasarCharacter(Point point, int centerX, int centerY) {
- int distance = (int) point.distance(centerX, centerY, 0);
- TextColor color;
- if (distance < 5) {
- color = lerpColor("#FFFFFF", "#87CEFA",
- distance / 5.0); // Interpolating between white and sky blue based on distance
- return new TextCharacter('o', color,
- TextColor.ANSI.BLACK); // Using '@' for denser core representation
- } else if (distance < 10) {
- color = lerpColor("#87CEFA", "#1E90FF",
- (distance - 5) / 5.0); // Interpolating between sky blue and deep blue
- return new TextCharacter('*', color,
- TextColor.ANSI.BLACK); // Using 'o' for intermediate representation
- } else if (distance < 15) {
- color = lerpColor("#1E90FF", "#00008B",
- (distance - 10) / 5.0); // Interpolating between deep blue and dark blue
- return new TextCharacter('+', color,
- TextColor.ANSI.BLACK); // Using '*' for outer representation
- } else {
- return new TextCharacter('.', TextColor.Factory.fromString("#00008B"),
- TextColor.ANSI.BLACK); // Dark blue for distant points
- }
- }
- @Value
- @AllArgsConstructor
- public class Point {
- double x;
- double y;
- double z;
- Optional<TextCharacter> character;
- public Point(double x, double y, double z) {
- this(x, y, z, Optional.empty());
- }
- public double distance(int x, int y, int z) {
- return Math.sqrt(Math.pow(this.x - x, 2) + Math.pow(this.y - y, 2) + Math.pow(this.z - z, 2));
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment