diff --git a/src/main/java/ru/mcs/q/TriangularBipyramidDemo.java b/src/main/java/ru/mcs/q/TriangularBipyramidDemo.java index 9e12d98..38a7fbc 100644 --- a/src/main/java/ru/mcs/q/TriangularBipyramidDemo.java +++ b/src/main/java/ru/mcs/q/TriangularBipyramidDemo.java @@ -3,45 +3,46 @@ import ru.mcs.q.field.FaceColor; import ru.mcs.q.field.QuantumFieldMesh3D; import ru.mcs.q.field.QuantumFieldVisualization; +import ru.mcs.q.field.Tetrahedron3D; import ru.mcs.q.field.Vector3D; import javax.swing.*; +import java.util.Map; public class TriangularBipyramidDemo { public static void main(String[] args) { - System.out.println("Starting Perfect Alignment Demo..."); + System.out.println("Starting Sequential Connection Demo..."); - // Создаем сетку тетраэдров QuantumFieldMesh3D mesh = new QuantumFieldMesh3D(); - // Создаем тетраэдры с начальными позициями, которые позволят им соединиться правильно + // Создаем тетраэдры в последовательности + // Сначала создаем центральный тетраэдр T1 mesh.addTetrahedron("T1", new Vector3D(0, 0, 0), 1.0); - mesh.addTetrahedron("T2", new Vector3D(3, 0, 0), 1.0); // Смещен в сторону для соединения красными гранями - mesh.addTetrahedron("T3", new Vector3D(0, 3, 0), 1.0); // Смещен вверх для соединения синими гранями - mesh.addTetrahedron("T4", new Vector3D(0, 0, 3), 1.0); // Смещен вперед для соединения зелеными гранями - mesh.addTetrahedron("T5", new Vector3D(3, 0, 0), 1.0); // Смещен влево для соединения с T2 - // Создаем соединения - теперь грани должны быть идеально параллельны - System.out.println("Creating perfectly aligned connections:"); + // Создаем T2, T3, T4 и соединяем их с T1 + mesh.addTetrahedron("T2", new Vector3D(2, 0, 0), 1.0); + mesh.addTetrahedron("T3", new Vector3D(0, 2, 0), 1.0); + mesh.addTetrahedron("T4", new Vector3D(0, 0, 2), 1.0); - // T1 и T2 соединяются красными гранями + // Соединяем T1 с T2, T3, T4 + System.out.println("Step 1: Connecting T1 with T2, T3, T4"); mesh.connectTetrahedrons("T1", FaceColor.RED, "T2", FaceColor.RED); - - // T1 и T3 соединяются синими гранями mesh.connectTetrahedrons("T1", FaceColor.BLUE, "T3", FaceColor.BLUE); - - // T1 и T4 соединяются зелеными гранями mesh.connectTetrahedrons("T1", FaceColor.GREEN, "T4", FaceColor.GREEN); - // T2 и T5 соединяются синими гранями + // Теперь создаем T5 и соединяем его с T2 + mesh.addTetrahedron("T5", new Vector3D(4, 0, 0), 1.0); + + System.out.println("Step 2: Connecting T2 with T5"); mesh.connectTetrahedrons("T2", FaceColor.BLUE, "T5", FaceColor.BLUE); - // Запускаем колебания + // Визуализируем нормали для отладки + visualizeConnections(mesh); + mesh.startFieldOscillations(); - // Создаем и показываем визуализацию SwingUtilities.invokeLater(() -> { - JFrame frame = new JFrame("Perfectly Aligned Quantum Field"); + JFrame frame = new JFrame("Sequential Connection Demo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); QuantumFieldVisualization visualization = new QuantumFieldVisualization(mesh); @@ -50,6 +51,17 @@ frame.setLocationRelativeTo(null); frame.setVisible(true); }); + } + private static void visualizeConnections(QuantumFieldMesh3D mesh) { + System.out.println("\n--- Connection Visualization ---"); + for (Tetrahedron3D tetra : mesh.getTetrahedrons().values()) { + System.out.println(tetra.getId() + " connections:"); + for (Map.Entry entry : tetra.getConnections().entrySet()) { + FaceColor color = entry.getKey(); + Tetrahedron3D connected = entry.getValue(); + System.out.printf(" %s → %s[%s]%n", color, connected.getId(), color); + } + } } } \ 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 index 248dc2a..2276885 100644 --- a/src/main/java/ru/mcs/q/field/QuantumFieldMesh3D.java +++ b/src/main/java/ru/mcs/q/field/QuantumFieldMesh3D.java @@ -30,6 +30,10 @@ return false; } + public Tetrahedron3D getTetrahedron(String id) { + return tetrahedrons.get(id); + } + public void startFieldOscillations() { if (!isActive) { isActive = true; @@ -49,20 +53,7 @@ tetrahedrons.values().forEach(tetrahedron -> { // Случайные колебания энергии double oscillation = (Math.random() - 0.5) * 0.1; - double newEnergy = Math.max(0, tetrahedron.getEnergyLevel() + oscillation); - - // Можно добавить небольшие случайные вращения для анимации - if (Math.random() < 0.3) { - // Случайное небольшое вращение - Vector3D randomAxis = new Vector3D( - Math.random() - 0.5, - Math.random() - 0.5, - Math.random() - 0.5 - ); - double angle = (Math.random() - 0.5) * 0.1; - Quaternion rotation = Quaternion.fromAxisAngle(randomAxis, angle); - tetrahedron.setOrientation(rotation.multiply(tetrahedron.getOrientation())); - } + tetrahedron.energyLevel = Math.max(0, tetrahedron.energyLevel + oscillation); }); } diff --git a/src/main/java/ru/mcs/q/field/Tetrahedron3D.java b/src/main/java/ru/mcs/q/field/Tetrahedron3D.java index 7134460..48bcd54 100644 --- a/src/main/java/ru/mcs/q/field/Tetrahedron3D.java +++ b/src/main/java/ru/mcs/q/field/Tetrahedron3D.java @@ -8,7 +8,7 @@ private Quaternion orientation; private final Map faces; private final Map connections; - private double energyLevel; + public double energyLevel; private final double size; // Вершины тетраэдра в локальной системе координат @@ -147,10 +147,10 @@ return false; } - if (face == otherFace && face != FaceColor.TRANSPARENT) { + if (face == otherFace) { if (!connections.containsKey(face) && !other.connections.containsKey(otherFace)) { - // Ориентируем тетраэдры для идеального параллельного соединения - alignFacesPerfectly(this, face, other, otherFace); + // Ориентируем второй тетраэдр относительно первого + orientRelativeTo(this, face, other, otherFace); connections.put(face, other); other.connections.put(otherFace, this); @@ -161,7 +161,7 @@ faces.put(face, FaceState.ATTRACTED); other.faces.put(otherFace, FaceState.ATTRACTED); - System.out.printf("Perfect parallel connection: %s[%s] ↔ %s[%s]%n", + System.out.printf("Connection: %s[%s] ↔ %s[%s]%n", id, face, other.id, otherFace); return true; } @@ -169,46 +169,42 @@ return false; } - private void alignFacesPerfectly(Tetrahedron3D tetra1, FaceColor face1, - Tetrahedron3D tetra2, FaceColor face2) { - int faceIndex1 = tetra1.getFaceIndex(face1); - int faceIndex2 = tetra2.getFaceIndex(face2); + private void orientRelativeTo(Tetrahedron3D reference, FaceColor refFace, + Tetrahedron3D target, FaceColor targetFace) { + int refFaceIndex = reference.getFaceIndex(refFace); + int targetFaceIndex = target.getFaceIndex(targetFace); - // Получаем нормали и центры граней в локальных координатах - Vector3D normal1 = tetra1.getLocalFaceNormal(faceIndex1); - Vector3D normal2 = tetra2.getLocalFaceNormal(faceIndex2); - Vector3D center1 = tetra1.getLocalFaceCenter(faceIndex1); - Vector3D center2 = tetra2.getLocalFaceCenter(faceIndex2); + // Получаем нормаль и центр грани референсного тетраэдра + Vector3D refNormal = reference.getFaceNormal(refFaceIndex); + Vector3D refCenter = reference.getFaceCenter(refFaceIndex); - // Мы хотим, чтобы нормаль второй грани была противоположна нормали первой - Vector3D desiredNormal2 = normal1.negate(); + // Получаем локальную нормаль целевой грани + Vector3D targetLocalNormal = target.getLocalFaceNormal(targetFaceIndex); - // Находим вращение, которое переводит normal2 в desiredNormal2 - Quaternion rotation = findRotation(normal2, desiredNormal2); + // Мы хотим, чтобы нормаль целевой грани была противоположна нормали референсной грани + Vector3D desiredTargetNormal = refNormal.negate(); - // Применяем это вращение ко второму тетраэдру - tetra2.orientation = rotation.multiply(tetra2.orientation); + // Находим вращение, которое переводит текущую мировую нормаль целевой грани в желаемую + Vector3D currentTargetNormal = target.getFaceNormal(targetFaceIndex); + Quaternion rotation = findRotation(currentTargetNormal, desiredTargetNormal); - // Теперь позиционируем тетраэдры так, чтобы грани были параллельны и обращены друг к другу - Vector3D worldFaceCenter1 = tetra1.getFaceCenter(faceIndex1); - Vector3D worldFaceCenter2 = tetra2.getFaceCenter(faceIndex2); + // Применяем вращение к целевому тетраэдру + target.orientation = rotation.multiply(target.orientation); - // Вычисляем вектор между центрами граней - Vector3D between = worldFaceCenter2.subtract(worldFaceCenter1); + // Позиционируем целевой тетраэдр так, чтобы грани были обращены друг к другу + Vector3D targetCenter = target.getFaceCenter(targetFaceIndex); + Vector3D between = targetCenter.subtract(refCenter); - // Мы хотим, чтобы этот вектор был параллелен нормали первой грани - // Проецируем вектор between на нормаль первой грани - Vector3D worldNormal1 = tetra1.getFaceNormal(faceIndex1); - double projectionLength = between.dot(worldNormal1); - Vector3D projection = worldNormal1.multiply(projectionLength); + // Проецируем вектор между центрами на нормаль референсной грани + double projection = between.dot(refNormal); + Vector3D correction = refNormal.multiply(projection); - // Корректируем позицию второго тетраэдра - Vector3D correction = between.subtract(projection); - tetra2.position = tetra2.position.subtract(correction); + // Корректируем позицию целевого тетраэдра + target.position = target.position.subtract(correction); - // Добавляем небольшое расстояние между гранями для визуализации + // Добавляем небольшое расстояние между гранями double separation = size * 0.1; - tetra2.position = tetra2.position.add(worldNormal1.multiply(separation)); + target.position = target.position.add(refNormal.multiply(separation)); } private Quaternion findRotation(Vector3D from, Vector3D to) {