diff --git a/source/defines.h b/source/defines.h index 772ef46..2713da3 100644 --- a/source/defines.h +++ b/source/defines.h @@ -132,6 +132,13 @@ constexpr float ICOSAHEDRON_ROTATION_SPEED_X = 0.4f; // Velocidad rotación eje constexpr float ICOSAHEDRON_ROTATION_SPEED_Y = 0.7f; // Velocidad rotación eje Y (rad/s) constexpr float ICOSAHEDRON_ROTATION_SPEED_Z = 0.2f; // Velocidad rotación eje Z (rad/s) +// Configuración de Atom (núcleo con órbitas electrónicas) +constexpr float ATOM_NUCLEUS_RADIUS_FACTOR = 0.08f; // Radio del núcleo central +constexpr float ATOM_ORBIT_RADIUS_FACTOR = 0.30f; // Radio de las órbitas +constexpr float ATOM_NUM_ORBITS = 3; // Número de órbitas +constexpr float ATOM_ORBIT_ROTATION_SPEED = 2.0f; // Velocidad de electrones (rad/s) +constexpr float ATOM_ROTATION_SPEED_Y = 0.5f; // Velocidad rotación global (rad/s) + // Control manual de escala de figuras 3D (Numpad +/-) constexpr float SHAPE_SCALE_MIN = 0.3f; // Escala mínima (30%) constexpr float SHAPE_SCALE_MAX = 3.0f; // Escala máxima (300%) diff --git a/source/engine.cpp b/source/engine.cpp index 89f78e1..3702333 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -30,6 +30,7 @@ #include "shapes/torus_shape.h" // for TorusShape #include "shapes/cylinder_shape.h" // for CylinderShape #include "shapes/icosahedron_shape.h" // for IcosahedronShape +#include "shapes/atom_shape.h" // for AtomShape // Función auxiliar para obtener la ruta del directorio del ejecutable std::string getExecutableDirectory() { @@ -1088,7 +1089,9 @@ void Engine::activateShape(ShapeType type) { case ShapeType::ICOSAHEDRON: active_shape_ = std::make_unique(); break; - // Futuras figuras se añadirán aquí + case ShapeType::ATOM: + active_shape_ = std::make_unique(); + break; default: active_shape_ = std::make_unique(); // Fallback break; diff --git a/source/shapes/atom_shape.cpp b/source/shapes/atom_shape.cpp new file mode 100644 index 0000000..4109a96 --- /dev/null +++ b/source/shapes/atom_shape.cpp @@ -0,0 +1,96 @@ +#include "atom_shape.h" +#include "../defines.h" +#include + +void AtomShape::generatePoints(int num_points, float screen_width, float screen_height) { + num_points_ = num_points; + nucleus_radius_ = screen_height * ATOM_NUCLEUS_RADIUS_FACTOR; + orbit_radius_ = screen_height * ATOM_ORBIT_RADIUS_FACTOR; + // Las posiciones se calculan en getPoint3D() +} + +void AtomShape::update(float delta_time, float screen_width, float screen_height) { + // Recalcular dimensiones por si cambió resolución (F4) + nucleus_radius_ = screen_height * ATOM_NUCLEUS_RADIUS_FACTOR; + orbit_radius_ = screen_height * ATOM_ORBIT_RADIUS_FACTOR; + + // Actualizar rotación global del átomo + angle_y_ += ATOM_ROTATION_SPEED_Y * delta_time; + + // Actualizar fase de rotación de electrones en órbitas + orbit_phase_ += ATOM_ORBIT_ROTATION_SPEED * delta_time; +} + +void AtomShape::getPoint3D(int index, float& x, float& y, float& z) const { + int num_orbits = static_cast(ATOM_NUM_ORBITS); + + // Calcular cuántos puntos para núcleo vs órbitas + int nucleus_points = (num_points_ < 10) ? 1 : (num_points_ / 10); // 10% para núcleo + if (nucleus_points < 1) nucleus_points = 1; + + // Si estamos en el núcleo + if (index < nucleus_points) { + // Distribuir puntos en esfera pequeña (núcleo) + float t = static_cast(index) / static_cast(nucleus_points); + float phi = acosf(1.0f - 2.0f * t); + float theta = PI * 2.0f * t * 3.61803398875f; // Golden ratio + + float x_nuc = nucleus_radius_ * cosf(theta) * sinf(phi); + float y_nuc = nucleus_radius_ * sinf(theta) * sinf(phi); + float z_nuc = nucleus_radius_ * cosf(phi); + + // Aplicar rotación global + float cos_y = cosf(angle_y_); + float sin_y = sinf(angle_y_); + x = x_nuc * cos_y - z_nuc * sin_y; + y = y_nuc; + z = x_nuc * sin_y + z_nuc * cos_y; + return; + } + + // Puntos restantes: distribuir en órbitas + int orbit_points = num_points_ - nucleus_points; + int points_per_orbit = orbit_points / num_orbits; + if (points_per_orbit < 1) points_per_orbit = 1; + + int orbit_index = (index - nucleus_points) / points_per_orbit; + if (orbit_index >= num_orbits) orbit_index = num_orbits - 1; + + int point_in_orbit = (index - nucleus_points) % points_per_orbit; + + // Ángulo del electrón en su órbita + float electron_angle = (static_cast(point_in_orbit) / static_cast(points_per_orbit)) * 2.0f * PI; + electron_angle += orbit_phase_; // Añadir rotación animada + + // Inclinación del plano orbital (cada órbita en ángulo diferente) + float orbit_tilt = (static_cast(orbit_index) / static_cast(num_orbits)) * PI; + + // Posición del electrón en su órbita (plano XY local) + float x_local = orbit_radius_ * cosf(electron_angle); + float y_local = orbit_radius_ * sinf(electron_angle); + float z_local = 0.0f; + + // Inclinar el plano orbital (rotación en eje X local) + float cos_tilt = cosf(orbit_tilt); + float sin_tilt = sinf(orbit_tilt); + float y_tilted = y_local * cos_tilt - z_local * sin_tilt; + float z_tilted = y_local * sin_tilt + z_local * cos_tilt; + + // Aplicar rotación global del átomo (eje Y) + float cos_y = cosf(angle_y_); + float sin_y = sinf(angle_y_); + float x_rot = x_local * cos_y - z_tilted * sin_y; + float z_rot = x_local * sin_y + z_tilted * cos_y; + + x = x_rot; + y = y_tilted; + z = z_rot; +} + +float AtomShape::getScaleFactor(float screen_height) const { + // Factor de escala para física: proporcional al radio de órbita + // Radio órbita base = 72px (0.30 * 240px en resolución 320x240) + const float BASE_RADIUS = 72.0f; + float current_radius = screen_height * ATOM_ORBIT_RADIUS_FACTOR; + return current_radius / BASE_RADIUS; +} diff --git a/source/shapes/atom_shape.h b/source/shapes/atom_shape.h new file mode 100644 index 0000000..2d79bf0 --- /dev/null +++ b/source/shapes/atom_shape.h @@ -0,0 +1,22 @@ +#pragma once + +#include "shape.h" + +// Figura: Átomo con núcleo central y órbitas electrónicas +// Comportamiento: Núcleo estático + electrones orbitando en planos inclinados +// Efecto: Modelo atómico clásico Bohr +class AtomShape : public Shape { +private: + float angle_y_ = 0.0f; // Ángulo de rotación global en eje Y (rad) + float orbit_phase_ = 0.0f; // Fase de rotación de electrones (rad) + float nucleus_radius_ = 0.0f; // Radio del núcleo central (píxeles) + float orbit_radius_ = 0.0f; // Radio de las órbitas (píxeles) + int num_points_ = 0; // Cantidad total de puntos + +public: + void generatePoints(int num_points, float screen_width, float screen_height) override; + void update(float delta_time, float screen_width, float screen_height) override; + void getPoint3D(int index, float& x, float& y, float& z) const override; + const char* getName() const override { return "ATOM"; } + float getScaleFactor(float screen_height) const override; +};