diff --git a/src/main/java/ru/mcs/q/VisualizationMain.java b/src/main/java/ru/mcs/q/VisualizationMain.java new file mode 100644 index 0000000..cbb3d6f --- /dev/null +++ b/src/main/java/ru/mcs/q/VisualizationMain.java @@ -0,0 +1,49 @@ +package ru.mcs.q; + +import ru.mcs.q.field.FaceColor; +import ru.mcs.q.field.QuantumFieldMesh3D; +import ru.mcs.q.field.QuantumFieldVisualization; +import ru.mcs.q.field.Vector3D; + +import javax.swing.*; + +public class VisualizationMain { + public static void main(String[] args) { + System.out.println("Starting 3D Quantum Field Visualization..."); + + // Создаем сетку тетраэдров + QuantumFieldMesh3D mesh = new QuantumFieldMesh3D(); + + // Добавляем тетраэдры в различных позициях + mesh.addTetrahedron("T1", new Vector3D(0, 0, 0), 0.5); + mesh.addTetrahedron("T2", new Vector3D(2, 0, 0), 0.5); + mesh.addTetrahedron("T3", new Vector3D(0, 2, 0), 0.5); + mesh.addTetrahedron("T4", new Vector3D(0, 0, 2), 0.5); + mesh.addTetrahedron("T5", new Vector3D(-2, 0, 0), 0.5); + mesh.addTetrahedron("T6", new Vector3D(1, 1, 1), 0.5); + mesh.addTetrahedron("T7", new Vector3D(-1, -1, -1), 0.5); + + // Создаем соединения + mesh.connectTetrahedrons("T1", FaceColor.RED, "T2", FaceColor.RED); + mesh.connectTetrahedrons("T1", FaceColor.BLUE, "T3", FaceColor.BLUE); + mesh.connectTetrahedrons("T1", FaceColor.GREEN, "T4", FaceColor.GREEN); + mesh.connectTetrahedrons("T2", FaceColor.BLUE, "T6", FaceColor.BLUE); + mesh.connectTetrahedrons("T3", FaceColor.GREEN, "T6", FaceColor.GREEN); + mesh.connectTetrahedrons("T5", FaceColor.RED, "T7", FaceColor.RED); + + // Запускаем колебания + mesh.startFieldOscillations(); + + // Создаем и показываем визуализацию + SwingUtilities.invokeLater(() -> { + JFrame frame = new JFrame("3D Quantum Field Visualization"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + QuantumFieldVisualization visualization = new QuantumFieldVisualization(mesh); + frame.add(visualization); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + } +} \ No newline at end of file diff --git a/src/main/java/ru/mcs/q/field/ProjectionUtils.java b/src/main/java/ru/mcs/q/field/ProjectionUtils.java new file mode 100644 index 0000000..ef50831 --- /dev/null +++ b/src/main/java/ru/mcs/q/field/ProjectionUtils.java @@ -0,0 +1,30 @@ +package ru.mcs.q.field; + +import java.awt.Point; + +public class ProjectionUtils { + + // Изометрическая проекция 3D -> 2D + public static Point projectIsometric(Vector3D point3D, double scale, Point center) { + double x2d = center.x + scale * (point3D.x - point3D.z) * Math.cos(Math.PI/6); + double y2d = center.y + scale * (point3D.y - (point3D.x + point3D.z) * Math.sin(Math.PI/6)); + return new Point((int)x2d, (int)y2d); + } + + // Перспективная проекция + public static Point projectPerspective(Vector3D point3D, double cameraDistance, double scale, Point center) { + double depth = cameraDistance - point3D.z; + if (depth <= 0) depth = 0.1; + + double x2d = center.x + scale * point3D.x / depth; + double y2d = center.y + scale * point3D.y / depth; + return new Point((int)x2d, (int)y2d); + } + + // Простая ортографическая проекция + public static Point projectOrthographic(Vector3D point3D, double scale, Point center) { + double x2d = center.x + scale * point3D.x; + double y2d = center.y + scale * point3D.y; + return new Point((int)x2d, (int)y2d); + } +} \ No newline at end of file diff --git a/src/main/java/ru/mcs/q/field/QuantumFieldMesh3D.java b/src/main/java/ru/mcs/q/field/QuantumFieldMesh3D.java new file mode 100644 index 0000000..5b5045d --- /dev/null +++ b/src/main/java/ru/mcs/q/field/QuantumFieldMesh3D.java @@ -0,0 +1,62 @@ +package ru.mcs.q.field; + +import java.util.*; +import java.util.concurrent.*; + +public class QuantumFieldMesh3D { + private final Map tetrahedrons; + private final ScheduledExecutorService scheduler; + private boolean isActive; + + public QuantumFieldMesh3D() { + this.tetrahedrons = new ConcurrentHashMap<>(); + this.scheduler = Executors.newScheduledThreadPool(1); + this.isActive = false; + } + + public void addTetrahedron(String id, Vector3D position, double size) { + Tetrahedron3D tetrahedron = new Tetrahedron3D(id, position, size); + tetrahedrons.put(id, tetrahedron); + System.out.println("Added " + tetrahedron); + } + + public boolean connectTetrahedrons(String id1, FaceColor face1, String id2, FaceColor face2) { + Tetrahedron3D t1 = tetrahedrons.get(id1); + Tetrahedron3D t2 = tetrahedrons.get(id2); + + if (t1 != null && t2 != null) { + return t1.connect(face1, t2, face2); + } + return false; + } + + public void startFieldOscillations() { + if (!isActive) { + isActive = true; + scheduler.scheduleAtFixedRate(this::updateField, 0, 2, TimeUnit.SECONDS); + } + } + + public void stopFieldOscillations() { + if (isActive) { + isActive = false; + scheduler.shutdown(); + } + } + + private void updateField() { + // Обновляем энергию и состояния + tetrahedrons.values().forEach(tetrahedron -> { + // Случайные колебания энергии + double oscillation = (Math.random() - 0.5) * 0.1; + double newEnergy = Math.max(0, tetrahedron.getEnergyLevel() + oscillation); + + // Обновляем размер в зависимости от энергии + double newSize = 0.5 + newEnergy * 0.5; + }); + } + + public Map getTetrahedrons() { + return Collections.unmodifiableMap(tetrahedrons); + } +} \ No newline at end of file diff --git a/src/main/java/ru/mcs/q/field/QuantumFieldVisualization.java b/src/main/java/ru/mcs/q/field/QuantumFieldVisualization.java new file mode 100644 index 0000000..086e472 --- /dev/null +++ b/src/main/java/ru/mcs/q/field/QuantumFieldVisualization.java @@ -0,0 +1,196 @@ +package ru.mcs.q.field; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import java.util.List; + +public class QuantumFieldVisualization extends JPanel { + private final QuantumFieldMesh3D mesh; + private double scale = 50; + private final Point center = new Point(400, 300); + private double rotationX = 0; + private double rotationY = 0; + private double cameraDistance = 5; + private String projectionType = "ISOMETRIC"; + + public QuantumFieldVisualization(QuantumFieldMesh3D mesh) { + this.mesh = mesh; + setPreferredSize(new Dimension(800, 600)); + setBackground(Color.WHITE); + + // Добавляем обработчики для вращения + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + // Переключение проекции по клику + switch (projectionType) { + case "ISOMETRIC" -> projectionType = "PERSPECTIVE"; + case "PERSPECTIVE" -> projectionType = "ORTHOGRAPHIC"; + default -> projectionType = "ISOMETRIC"; + } + repaint(); + } + }); + + addMouseMotionListener(new MouseMotionAdapter() { + private int lastX, lastY; + + @Override + public void mouseDragged(MouseEvent e) { + int dx = e.getX() - lastX; + int dy = e.getY() - lastY; + + rotationY += dx * 0.01; + rotationX += dy * 0.01; + + lastX = e.getX(); + lastY = e.getY(); + repaint(); + } + + @Override + public void mouseMoved(MouseEvent e) { + lastX = e.getX(); + lastY = e.getY(); + } + }); + + addMouseWheelListener(e -> { + scale += e.getWheelRotation() * 5; + scale = Math.max(10, Math.min(200, scale)); + repaint(); + }); + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2d = (Graphics2D) g; + + // Включаем сглаживание + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + // Рисуем соединения + drawConnections(g2d); + + // Рисуем тетраэдры + drawTetrahedrons(g2d); + + // Рисуем информацию + drawInfo(g2d); + } + + private void drawConnections(Graphics2D g2d) { + for (Tetrahedron3D tetra : mesh.getTetrahedrons().values()) { + Vector3D pos1 = tetra.getPosition(); + + for (Map.Entry entry : tetra.getConnections().entrySet()) { + Tetrahedron3D connected = entry.getValue(); + FaceColor color = entry.getKey(); + + Vector3D pos2 = connected.getPosition(); + + // Рисуем линию соединения + Point p1 = projectPoint(rotatePoint(pos1)); + Point p2 = projectPoint(rotatePoint(pos2)); + + g2d.setColor(toAwtColor(color)); + g2d.setStroke(new BasicStroke(2)); + g2d.drawLine(p1.x, p1.y, p2.x, p2.y); + } + } + } + + private void drawTetrahedrons(Graphics2D g2d) { + for (Tetrahedron3D tetra : mesh.getTetrahedrons().values()) { + drawTetrahedron(g2d, tetra); + } + } + + private void drawTetrahedron(Graphics2D g2d, Tetrahedron3D tetra) { + Vector3D[] vertices = tetra.getWorldVertices(); + int[][] faces = tetra.getFacesIndices(); + + // Проецируем и вращаем все вершины + Point[] projectedVertices = new Point[vertices.length]; + for (int i = 0; i < vertices.length; i++) { + projectedVertices[i] = projectPoint(rotatePoint(vertices[i])); + } + + // Рисуем грани + for (int i = 0; i < faces.length; i++) { + int[] face = faces[i]; + FaceColor faceColor = tetra.getFaceColor(i); + + // Пропускаем прозрачные грани + if (faceColor == FaceColor.TRANSPARENT) continue; + + Polygon polygon = new Polygon(); + for (int vertexIndex : face) { + Point p = projectedVertices[vertexIndex]; + polygon.addPoint(p.x, p.y); + } + + // Заливаем грань цветом с прозрачностью + Color fillColor = toAwtColor(faceColor); + g2d.setColor(new Color(fillColor.getRed(), fillColor.getGreen(), fillColor.getBlue(), 100)); + g2d.fill(polygon); + + // Рисуем контур + g2d.setColor(fillColor); + g2d.setStroke(new BasicStroke(1)); + g2d.draw(polygon); + } + + // Рисуем центр тетраэдра + Point centerPoint = projectPoint(rotatePoint(tetra.getPosition())); + g2d.setColor(Color.BLACK); + g2d.fillOval(centerPoint.x - 3, centerPoint.y - 3, 6, 6); + + // Подписываем тетраэдр + g2d.drawString(tetra.getId(), centerPoint.x + 5, centerPoint.y - 5); + + // Показываем энергию + g2d.setColor(Color.DARK_GRAY); + g2d.drawString(String.format("%.1f", tetra.getEnergyLevel()), centerPoint.x + 5, centerPoint.y + 15); + } + + private Vector3D rotatePoint(Vector3D point) { + // Вращение вокруг оси Y + double x1 = point.x * Math.cos(rotationY) - point.z * Math.sin(rotationY); + double z1 = point.x * Math.sin(rotationY) + point.z * Math.cos(rotationY); + + // Вращение вокруг оси X + double y1 = point.y * Math.cos(rotationX) - z1 * Math.sin(rotationX); + double z2 = point.y * Math.sin(rotationX) + z1 * Math.cos(rotationX); + + return new Vector3D(x1, y1, z2); + } + + private Point projectPoint(Vector3D point) { + return switch (projectionType) { + case "PERSPECTIVE" -> ProjectionUtils.projectPerspective(point, cameraDistance, scale, center); + case "ORTHOGRAPHIC" -> ProjectionUtils.projectOrthographic(point, scale, center); + default -> ProjectionUtils.projectIsometric(point, scale, center); + }; + } + + private Color toAwtColor(FaceColor color) { + return switch (color) { + case RED -> Color.RED; + case BLUE -> Color.BLUE; + case GREEN -> Color.GREEN; + case TRANSPARENT -> new Color(200, 200, 200, 100); + }; + } + + private void drawInfo(Graphics2D g2d) { + g2d.setColor(Color.BLACK); + g2d.drawString("Projection: " + projectionType, 10, 20); + g2d.drawString("Scale: " + scale, 10, 40); + g2d.drawString("Tetrahedrons: " + mesh.getTetrahedrons().size(), 10, 60); + g2d.drawString("Click to change projection, Drag to rotate, Scroll to zoom", 10, 80); + } +} \ No newline at end of file diff --git a/src/main/java/ru/mcs/q/field/Tetrahedron3D.java b/src/main/java/ru/mcs/q/field/Tetrahedron3D.java new file mode 100644 index 0000000..1dec243 --- /dev/null +++ b/src/main/java/ru/mcs/q/field/Tetrahedron3D.java @@ -0,0 +1,105 @@ +package ru.mcs.q.field; + +import java.awt.Color; +import java.util.*; + +public class Tetrahedron3D { + private final String id; + private Vector3D position; + private final Map faces; + private final Map connections; + private double energyLevel; + private double size; + + // Вершины тетраэдра относительно его центра + private final Vector3D[] vertices; + + public Tetrahedron3D(String id, Vector3D position, double size) { + this.id = id; + this.position = position; + this.size = size; + this.faces = new EnumMap<>(FaceColor.class); + this.connections = new EnumMap<>(FaceColor.class); + this.energyLevel = 0.0; + + // Инициализируем все грани + for (FaceColor color : FaceColor.values()) { + faces.put(color, FaceState.NEUTRAL); + } + + // Вычисляем вершины тетраэдра + this.vertices = calculateVertices(); + } + + private Vector3D[] calculateVertices() { + Vector3D[] verts = new Vector3D[4]; + + // Вершины правильного тетраэдра + double a = size; + verts[0] = new Vector3D(0, 0, a * Math.sqrt(2.0/3.0)); // Верхняя вершина + verts[1] = new Vector3D(0, a/Math.sqrt(3), -a/Math.sqrt(6)); // Основание + verts[2] = new Vector3D(a/2, -a/(2*Math.sqrt(3)), -a/Math.sqrt(6)); // Основание + verts[3] = new Vector3D(-a/2, -a/(2*Math.sqrt(3)), -a/Math.sqrt(6)); // Основание + + return verts; + } + + public Vector3D[] getWorldVertices() { + Vector3D[] worldVerts = new Vector3D[4]; + for (int i = 0; i < 4; i++) { + worldVerts[i] = vertices[i].add(position); + } + return worldVerts; + } + + // Грани тетраэдра (индексы вершин) + public int[][] getFacesIndices() { + return new int[][] { + {0, 1, 2}, // Грань 0 + {0, 2, 3}, // Грань 1 + {0, 3, 1}, // Грань 2 + {1, 3, 2} // Грань 3 (основание) + }; + } + + public FaceColor getFaceColor(int faceIndex) { + FaceColor[] colors = {FaceColor.RED, FaceColor.BLUE, FaceColor.GREEN, FaceColor.TRANSPARENT}; + return colors[faceIndex]; + } + + public boolean connect(FaceColor face, Tetrahedron3D other, FaceColor otherFace) { + if (other == null) { + return false; + } + + if (face == otherFace && face != FaceColor.TRANSPARENT) { + if (!connections.containsKey(face) && !other.connections.containsKey(otherFace)) { + connections.put(face, other); + other.connections.put(otherFace, this); + + this.energyLevel += 0.1; + other.energyLevel += 0.1; + + faces.put(face, FaceState.ATTRACTED); + other.faces.put(otherFace, FaceState.ATTRACTED); + + return true; + } + } + return false; + } + + // Getters + public String getId() { return id; } + public Vector3D getPosition() { return position; } + public void setPosition(Vector3D position) { this.position = position; } + public double getEnergyLevel() { return energyLevel; } + public Map getFaces() { return faces; } + public Map getConnections() { return connections; } + public double getSize() { return size; } + + @Override + public String toString() { + return String.format("Tetrahedron3D[%s] pos=%s energy=%.2f", id, position, energyLevel); + } +} \ No newline at end of file diff --git a/src/main/java/ru/mcs/q/field/Vector3D.java b/src/main/java/ru/mcs/q/field/Vector3D.java new file mode 100644 index 0000000..fa97804 --- /dev/null +++ b/src/main/java/ru/mcs/q/field/Vector3D.java @@ -0,0 +1,24 @@ +package ru.mcs.q.field; + +public class Vector3D { + public double x, y, z; + + public Vector3D(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + public Vector3D add(Vector3D other) { + return new Vector3D(x + other.x, y + other.y, z + other.z); + } + + public Vector3D multiply(double scalar) { + return new Vector3D(x * scalar, y * scalar, z * scalar); + } + + @Override + public String toString() { + return String.format("(%.2f, %.2f, %.2f)", x, y, z); + } +} \ No newline at end of file