From 267e54f974a4af5f0e89eae5126985d4498d6bc0 Mon Sep 17 00:00:00 2001 From: sergio Date: Fri, 22 May 2026 19:29:50 +0000 Subject: [PATCH] =?UTF-8?q?feat(cosmobiologia):=20esfera=203D=20=E2=80=94?= =?UTF-8?q?=20figuras=20de=20las=2088=20constelaciones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Las constelaciones de un catálogo REAL, no inventadas de memoria: d3-celestial (dominio público), 89 figuras / 743 segmentos, en coordenadas ecuatoriales J2000. El dataset se convirtió a un módulo Rust generado (`constellations_data.rs`) — datos en el repo, auditables. Cada figura: sus polilíneas unen estrellas reales del catálogo (un punto por vértice) y el nombre va en el centroide. Capa tenue, atenuada por profundidad — referencia, no protagonista. Se convierten al marco eclíptico con la misma rotación por oblicuidad que el resto. 42 tests verdes. Co-Authored-By: Claude Opus 4.7 --- .../src/constellations_data.rs | 344 ++++++++++++++++++ .../cosmobiologia-render/src/lib.rs | 1 + .../cosmobiologia-render/src/sphere3d.rs | 123 ++++++- 3 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 crates/modules/cosmobiologia/cosmobiologia-render/src/constellations_data.rs diff --git a/crates/modules/cosmobiologia/cosmobiologia-render/src/constellations_data.rs b/crates/modules/cosmobiologia/cosmobiologia-render/src/constellations_data.rs new file mode 100644 index 0000000..4be288f --- /dev/null +++ b/crates/modules/cosmobiologia/cosmobiologia-render/src/constellations_data.rs @@ -0,0 +1,344 @@ +//! Figuras de constelaciones — ARCHIVO GENERADO, no editar a mano. +//! +//! Fuente: d3-celestial (github.com/ofrohn/d3-celestial), de dominio +//! público. Cada figura es un conjunto de polilíneas en coordenadas +//! ecuatoriales (AR, Dec) en grados, época J2000. La esfera 3D las +//! convierte al marco eclíptico y las proyecta. + +/// Una figura de constelación: su nombre y sus polilíneas (trazos +/// abiertos de la figura de estrellas). +pub struct Figura { + pub nombre: &'static str, + pub paths: &'static [&'static [(f32, f32)]], +} + +pub const FIGURAS: &[Figura] = &[ + Figura { nombre: "Andromeda", paths: &[ + &[(30.9748, 42.3297), (17.4330, 35.6206), (9.8320, 30.8610), (2.0969, 29.0904)], + &[(14.3017, 23.4176), (11.8347, 24.2672), (9.6389, 29.3118), (9.8320, 30.8610), (9.2202, 33.7193), (-5.4658, 43.2681), (-14.5197, 42.3260)], + &[(-5.4658, 43.2681), (-4.8979, 44.3339), (-5.6090, 46.4582)], + &[(17.4330, 35.6206), (14.1884, 38.4993), (12.4535, 41.0789), (17.3755, 47.2418), (24.4982, 48.6282)], + &[(-4.8979, 44.3339), (-3.4915, 46.4203)], + ] }, + Figura { nombre: "Antlia", paths: &[ + &[(142.3113, -35.9513), (156.7879, -31.0678), (164.1794, -37.1378)], + ] }, + Figura { nombre: "Apus", paths: &[ + &[(-138.0345, -79.0448), (-114.9133, -78.6957), (-109.2306, -77.5174), (-111.6372, -78.8971)], + ] }, + Figura { nombre: "Aquarius", paths: &[ + &[(-48.0810, -9.4958), (-46.8365, -8.9833), (-37.1103, -5.5712), (-28.5540, -0.3199), (-24.5859, -1.3873), (-22.7920, -0.0200), (-21.1609, -0.1175), (-16.8464, -7.5796), (-10.5241, -9.1825), (-12.6383, -21.1724)], + &[(-37.1103, -5.5712), (-28.3907, -13.8697)], + &[(-28.5540, -0.3199), (-25.7915, -7.7833)], + &[(-22.7920, -0.0200), (-23.6807, 1.3774)], + &[(-9.2574, -20.1006), (-10.5241, -9.1825), (-4.5591, -17.8165)], + ] }, + Figura { nombre: "Aquila", paths: &[ + &[(-63.4351, 10.6133), (-62.3042, 8.8683), (-61.1717, 6.4068), (-57.1738, -0.8215), (-61.8818, 1.0057), (-68.6254, 3.1148), (-73.6475, 13.8635), (-62.3042, 8.8683), (-68.6254, 3.1148), (-73.4378, -4.8826)], + ] }, + Figura { nombre: "Ara", paths: &[ + &[(-98.6514, -56.3777), (-97.2254, -60.6838), (-107.5535, -59.0414), (-105.3450, -55.9901), (-105.1040, -53.1604), (-97.0396, -49.8761), (-98.6750, -55.5299)], + ] }, + Figura { nombre: "Aries", paths: &[ + &[(42.4960, 27.2605), (31.7934, 23.4624), (28.6600, 20.8080), (28.3826, 19.2939)], + ] }, + Figura { nombre: "Auriga", paths: &[ + &[(89.8822, 44.9474), (79.1723, 45.9980), (76.6287, 41.2345), (74.2484, 33.1661), (81.5730, 28.6075), (89.9303, 37.2126), (89.8822, 44.9474), (89.8818, 54.2847), (79.1723, 45.9980), (75.4922, 43.8233), (75.6195, 41.0758)], + ] }, + Figura { nombre: "Boötes", paths: &[ + &[(-153.1844, 17.4569), (-151.3288, 18.3977), (-146.0847, 19.1824), (-142.0425, 30.3714), (-141.9805, 38.3083), (-134.5135, 40.3906), (-131.1243, 33.3148), (-138.7533, 27.0742), (-146.0847, 19.1824), (-139.7127, 13.7283)], + &[(-141.9805, 38.3083), (-145.9041, 46.0883), (-146.6341, 51.7879), (-143.7008, 51.8507), (-145.9041, 46.0883)], + ] }, + Figura { nombre: "Caelum", paths: &[ + &[(67.7087, -44.9537), (70.1405, -41.8638), (70.5145, -37.1443), (76.1017, -35.4830)], + ] }, + Figura { nombre: "Camelopardalis", paths: &[ + &[(74.3217, 53.7521), (75.8545, 60.4422), (73.5125, 66.3427), (57.5896, 71.3323), (57.3803, 65.5260), (52.2672, 59.9403)], + &[(73.5125, 66.3427), (94.7116, 69.3198), (105.0168, 76.9774)], + ] }, + Figura { nombre: "Cancer", paths: &[ + &[(134.6218, 11.8577), (131.1712, 18.1543), (130.8214, 21.4685), (131.6666, 28.7651)], + &[(131.1712, 18.1543), (124.1288, 9.1855)], + ] }, + Figura { nombre: "Canes Venatici", paths: &[ + &[(-165.9981, 38.3149), (-171.5644, 41.3575)], + ] }, + Figura { nombre: "Canis Major", paths: &[ + &[(95.6749, -17.9559), (101.2872, -16.7161), (105.7561, -23.8333), (107.0979, -26.3932), (105.4298, -27.9348), (104.6565, -28.9721), (95.0783, -30.0634)], + &[(111.0238, -29.3031), (107.0979, -26.3932)], + &[(101.2872, -16.7161), (104.0343, -17.0542), (105.9396, -15.6333), (103.5475, -12.0386), (104.0343, -17.0542)], + ] }, + Figura { nombre: "Canis Minor", paths: &[ + &[(114.8255, 5.2250), (111.7877, 8.2893)], + ] }, + Figura { nombre: "Capricornus", paths: &[ + &[(-55.5880, -12.5082), (-54.7472, -14.7814), (-52.7849, -17.8137), (-48.4761, -25.2709), (-47.0446, -26.9191), (-38.3332, -22.4113), (-33.2398, -16.1273), (-34.9773, -16.6623), (-39.4383, -16.8345), (-43.5132, -17.2329), (-55.5880, -12.5082)], + ] }, + Figura { nombre: "Carina", paths: &[ + &[(99.4403, -43.1959), (95.9880, -52.6957), (138.2999, -69.7172), (153.4342, -70.0379), (160.7392, -64.3945), (158.0061, -61.6853), (154.2707, -61.3323), (139.2725, -59.2752), (125.6285, -59.5095), (119.1946, -52.9824), (122.3831, -47.3366), (131.1759, -54.7088), (139.2725, -59.2752)], + &[(160.7392, -64.3945), (166.6351, -62.4241), (167.1417, -61.9472), (168.1501, -60.3176), (167.1475, -58.9750), (163.3736, -58.8532), (158.0061, -61.6853)], + ] }, + Figura { nombre: "Cassiopeia", paths: &[ + &[(28.5989, 63.6701), (21.4540, 60.2353), (14.1772, 60.7167), (10.1268, 56.5373), (2.2945, 59.1498)], + ] }, + Figura { nombre: "Centaurus", paths: &[ + &[(170.2517, -54.4910), (-177.9104, -50.7224), (-172.9901, -50.2306), (-169.6207, -48.9599), (-155.0281, -53.4664), (-151.1151, -47.2884), (-152.5959, -42.4737), (-152.6238, -41.6877), (-148.3294, -36.3700), (-141.1232, -42.1578), (-135.2096, -42.1042)], + &[(-152.6238, -41.6877), (-159.8508, -36.7123)], + &[(-140.1038, -60.8372), (-155.0281, -53.4664), (-149.0441, -60.3730)], + &[(-172.9901, -50.2306), (-177.0870, -52.3685), (172.9420, -59.4421)], + ] }, + Figura { nombre: "Cepheus", paths: &[ + &[(-52.6046, 62.9941), (-48.6776, 61.8388), (-40.3551, 62.5856), (-34.1231, 58.7800), (-26.2409, 57.0436), (-27.2863, 58.2013), (-22.7072, 58.4152), (-17.5799, 66.2004), (-5.1631, 77.6323), (-37.8350, 70.5607), (-40.3551, 62.5856)], + &[(-37.8350, 70.5607), (-17.5799, 66.2004)], + ] }, + Figura { nombre: "Cetus", paths: &[ + &[(40.8252, 3.2358), (38.9686, 5.5932), (37.0398, 8.4601), (41.2356, 10.1141), (44.9288, 8.9074), (45.5699, 4.0897), (40.8252, 3.2358), (39.8707, 0.3285), (34.8366, -2.9776), (27.8651, -10.3350), (26.0170, -15.9375), (10.8974, -17.9866), (4.8570, -8.8239), (17.1475, -10.1823), (21.0059, -8.1833), (27.8651, -10.3350)], + ] }, + Figura { nombre: "Chamaeleon", paths: &[ + &[(124.6315, -76.9197), (158.8671, -78.6078), (161.3180, -80.4696), (-175.4132, -79.3122), (179.9066, -78.2218), (158.8671, -78.6078)], + ] }, + Figura { nombre: "Circinus", paths: &[ + &[(-130.6215, -58.8012), (-139.3733, -64.9751), (-129.1556, -59.3208)], + ] }, + Figura { nombre: "Columba", paths: &[ + &[(95.5285, -33.4364), (87.7400, -35.7683), (84.9122, -34.0741), (82.8031, -35.4705)], + &[(87.7400, -35.7683), (89.7867, -42.8151)], + ] }, + Figura { nombre: "Coma Berenices", paths: &[ + &[(-162.5030, 17.5294), (-162.0317, 27.8782), (-173.2655, 28.2684)], + ] }, + Figura { nombre: "Corona Austrina", paths: &[ + &[(-75.3193, -37.1074), (-73.3954, -37.0634), (-72.6319, -37.9045), (-72.4927, -39.3408), (-72.9126, -40.4967), (-74.2213, -42.0951), (-77.6042, -43.4341), (-81.6242, -42.3125)], + ] }, + Figura { nombre: "Corona Borealis", paths: &[ + &[(-126.7676, 31.3591), (-128.0428, 29.1057), (-126.3280, 26.7147), (-124.3143, 26.2956), (-122.6015, 26.0684), (-120.6031, 26.8779), (-119.6393, 29.8511)], + ] }, + Figura { nombre: "Corvus", paths: &[ + &[(-177.8966, -24.7289), (-177.4688, -22.6198), (-176.0485, -17.5419), (-172.5339, -16.5154), (-171.4032, -23.3968), (-177.4688, -22.6198)], + ] }, + Figura { nombre: "Crater", paths: &[ + &[(174.1705, -9.8022), (171.1525, -10.8593), (169.8352, -14.7785), (164.9436, -18.2988), (167.9145, -22.8258), (170.8412, -18.7800), (171.2205, -17.6840), (176.1907, -18.3507), (179.0040, -17.1508)], + &[(169.8352, -14.7785), (171.2205, -17.6840)], + ] }, + Figura { nombre: "Crux", paths: &[ + &[(-168.0697, -59.6888), (-176.2137, -58.7489)], + &[(-173.3504, -63.0991), (-172.2085, -57.1132)], + ] }, + Figura { nombre: "Cygnus", paths: &[ + &[(-41.7659, 30.2269), (-48.4472, 33.9703), (-54.4429, 40.2567), (-63.7563, 45.1308), (-67.5735, 51.7298), (-70.7243, 53.3685)], + &[(-49.6420, 45.2803), (-54.4429, 40.2567), (-60.9235, 35.0834), (-67.3197, 27.9597)], + ] }, + Figura { nombre: "Delphinus", paths: &[ + &[(-51.6968, 11.3033), (-50.6127, 14.5951), (-50.0905, 15.9121), (-48.3381, 16.1241), (-49.1353, 15.0746), (-50.6127, 14.5951)], + ] }, + Figura { nombre: "Dorado", paths: &[ + &[(64.0066, -51.4866), (68.4991, -55.0450), (83.4063, -62.4898), (86.1932, -65.7355), (88.5252, -63.0896), (83.4063, -62.4898), (76.3777, -57.4727), (68.4991, -55.0450)], + ] }, + Figura { nombre: "Draco", paths: &[ + &[(-91.6178, 56.8726), (-90.8485, 51.4889), (-97.3918, 52.3014), (-96.9332, 55.1730), (-91.6178, 56.8726), (-71.8612, 67.6615), (-84.8107, 71.3378), (-102.8034, 65.7147), (-114.0021, 61.5142), (-119.5277, 58.5653), (-128.7676, 58.9661), (-148.9027, 64.3759), (-171.6294, 69.7882), (172.8509, 69.3311)], + &[(-84.8107, 71.3378), (-84.7359, 72.7328)], + &[(-71.8612, 67.6615), (-62.9569, 70.2679)], + ] }, + Figura { nombre: "Equuleus", paths: &[ + &[(-41.0440, 5.2478), (-41.3799, 10.0070), (-42.4146, 10.1316)], + ] }, + Figura { nombre: "Eridanus", paths: &[ + &[(76.9624, -5.0864), (71.3756, -3.2547), (69.0798, -3.3525), (62.9664, -6.8376), (59.5074, -13.5085), (56.5356, -12.1016), (55.8121, -9.7634), (53.2327, -9.4583), (44.1069, -8.8981), (41.0306, -13.8587), (41.2758, -18.5726), (45.5979, -23.6245), (49.8792, -21.7579), (53.4470, -21.6329), (56.7120, -23.2497), (68.8877, -30.5623), (66.0092, -34.0168), (64.4736, -33.7983), (57.3635, -36.2003), (54.2737, -40.2745), (49.9819, -43.0698), (44.5653, -40.3047), (40.1668, -39.8554), (36.7463, -47.7038), (34.1274, -51.5122), (28.9895, -51.6089), (24.4285, -57.2368)], + ] }, + Figura { nombre: "Fornax", paths: &[ + &[(48.0189, -28.9876), (42.2726, -32.4059), (31.1227, -29.2968)], + ] }, + Figura { nombre: "Gemini", paths: &[ + &[(93.7194, 22.5068), (95.7401, 22.5136), (100.9830, 25.1311), (107.7849, 30.2452), (113.6494, 31.8883), (116.3290, 28.0262), (113.9806, 26.8957), (110.0307, 21.9823), (106.0272, 20.5703), (99.4279, 16.3993), (101.3224, 12.8956)], + &[(110.0307, 21.9823), (109.5232, 16.5404)], + ] }, + Figura { nombre: "Grus", paths: &[ + &[(-14.7800, -52.7541), (-17.8613, -51.3169), (-19.3331, -46.8846), (-22.5607, -43.7492), (-27.9417, -46.9610), (-19.3331, -46.8846)], + &[(-22.6826, -43.4956), (-26.0962, -41.3467), (-28.4713, -39.5434), (-31.5178, -37.3649)], + ] }, + Figura { nombre: "Hercules", paths: &[ + &[(-114.5199, 19.1531), (-112.4450, 21.4896), (-109.6785, 31.6027), (-109.2760, 38.9223), (-111.4742, 42.4370), (-115.0648, 46.3134), (-117.8076, 44.9349), (-121.8311, 42.4515)], + &[(-109.6785, 31.6027), (-104.9276, 30.9264)], + &[(-109.2760, 38.9223), (-101.2382, 36.8092)], + &[(-90.9367, 37.2505), (-99.0794, 37.1459), (-101.2382, 36.8092), (-104.9276, 30.9264), (-101.2420, 24.8392), (-93.3853, 27.7207), (-90.5588, 29.2479), (-88.1144, 28.7625)], + &[(-101.3381, 14.3903), (-112.4450, 21.4896)], + ] }, + Figura { nombre: "Horologium", paths: &[ + &[(63.5005, -42.2944), (40.6394, -50.8003), (39.3515, -52.5431), (40.1651, -54.5499), (45.9034, -59.7378), (44.6992, -64.0713)], + ] }, + Figura { nombre: "Hydra", paths: &[ + &[(131.6938, 6.4188), (132.1082, 5.8378), (130.8061, 3.3987), (129.6893, 3.3414), (129.4140, 5.7038), (131.6938, 6.4188), (133.8484, 5.9456), (138.5911, 2.3143), (144.9640, -1.1428), (141.8968, -8.6586), (147.8696, -14.8466), (152.6470, -12.3541), (156.5226, -16.8363), (162.4062, -16.1936), (173.2505, -31.8576), (178.2272, -33.9081), (-160.2696, -23.1715), (-148.4071, -26.6824), (-137.4279, -27.9604)], + ] }, + Figura { nombre: "Hydrus", paths: &[ + &[(6.4378, -77.2542), (56.8098, -74.2390), (39.8973, -68.2669), (35.4373, -68.6594), (28.7339, -67.6473), (29.6925, -61.5699)], + ] }, + Figura { nombre: "Indus", paths: &[ + &[(-50.6082, -47.2915), (-48.9903, -51.9210), (-46.2975, -58.4542), (-30.5205, -54.9926), (-40.0334, -53.4494), (-50.6082, -47.2915)], + ] }, + Figura { nombre: "Lacerta", paths: &[ + &[(-24.1099, 52.2290), (-22.1771, 50.2825), (-22.6174, 47.7069), (-24.7436, 46.5366), (-22.3781, 43.1234), (-19.8714, 44.2763), (-22.6174, 47.7069), (-23.8709, 49.4764), (-24.1099, 52.2290)], + &[(-22.3781, 43.1234), (-26.5303, 39.7149), (-26.0076, 37.7487)], + ] }, + Figura { nombre: "Leo", paths: &[ + &[(152.0930, 11.9672), (151.8331, 16.7627), (154.9931, 19.8415), (168.5271, 20.5237), (177.2649, 14.5721), (168.5600, 15.4296), (152.0930, 11.9672)], + &[(154.9931, 19.8415), (154.1726, 23.4173), (148.1909, 26.0070), (146.4628, 23.7743)], + ] }, + Figura { nombre: "Leo Minor", paths: &[ + &[(151.8573, 35.2447), (156.4784, 33.7961), (163.3279, 34.2149), (156.9708, 36.7072), (151.8573, 35.2447), (143.5558, 36.3976)], + ] }, + Figura { nombre: "Lepus", paths: &[ + &[(91.5388, -14.9353), (89.1012, -14.1677), (86.7389, -14.8220), (83.1826, -17.8223), (78.2329, -16.2055), (76.3653, -22.3710), (82.0613, -20.7594), (86.1158, -22.4484), (87.8304, -20.8791)], + &[(78.3078, -12.9413), (78.2329, -16.2055), (79.8939, -13.1768)], + ] }, + Figura { nombre: "Libra", paths: &[ + &[(-133.9824, -25.2820), (-137.2804, -16.0418), (-130.7483, -9.3829), (-126.1184, -14.7895), (-125.7440, -28.1351), (-125.3360, -29.7778)], + &[(-137.2804, -16.0418), (-126.1184, -14.7895)], + ] }, + Figura { nombre: "Lupus", paths: &[ + &[(-122.2603, -33.6272), (-125.0584, -34.4119), (-129.5485, -36.2614), (-129.6570, -40.6475), (-135.3670, -43.1340), (-139.5177, -47.3882), (-131.9288, -52.0992), (-130.3666, -47.8753), (-129.3297, -44.6896), (-126.2148, -41.1668), (-119.9695, -38.3967), (-118.3519, -36.8023)], + &[(-129.6570, -40.6475), (-126.2148, -41.1668)], + ] }, + Figura { nombre: "Lynx", paths: &[ + &[(94.9058, 59.0110), (104.3192, 58.4228), (111.6785, 49.2115), (125.7088, 43.1881), (135.1599, 41.7829), (139.7110, 36.8026), (140.2638, 34.3926)], + ] }, + Figura { nombre: "Lyra", paths: &[ + &[(-78.8068, 37.6051), (-78.9051, 39.6127), (-80.7653, 38.7837), (-78.8068, 37.6051), (-76.3738, 36.8986), (-75.2641, 32.6896), (-77.4800, 33.3627), (-78.8068, 37.6051)], + ] }, + Figura { nombre: "Mensa", paths: &[ + &[(92.5603, -74.7530), (82.9709, -76.3410), (73.7967, -74.9369), (75.6792, -71.3143)], + ] }, + Figura { nombre: "Microscopium", paths: &[ + &[(-47.5080, -33.7797), (-47.8786, -43.9885), (-39.8098, -40.8095), (-40.5155, -32.1725), (-44.6772, -32.2578), (-47.5080, -33.7797)], + ] }, + Figura { nombre: "Monoceros", paths: &[ + &[(115.3118, -9.5511), (122.1485, -2.9838), (107.9661, -0.4928), (97.2045, -7.0331), (93.7139, -6.2748)], + &[(107.9661, -0.4928), (101.9652, 2.4122), (95.9420, 4.5929), (98.2259, 7.3330), (100.2444, 9.8958)], + ] }, + Figura { nombre: "Musca", paths: &[ + &[(176.4017, -66.7288), (-175.6072, -67.9607), (-170.7041, -69.1356), (-168.4300, -68.1081), (-164.4322, -71.5489), (-171.8833, -72.1330), (-170.7041, -69.1356)], + ] }, + Figura { nombre: "Norma", paths: &[ + &[(-118.3773, -45.1732), (-113.2040, -47.5548), (-115.0399, -50.1555), (-119.1963, -49.2297), (-118.3773, -45.1732)], + ] }, + Figura { nombre: "Octans", paths: &[ + &[(-143.2699, -83.6679), (-18.4854, -81.3816), (-34.6306, -77.3900), (-143.2699, -83.6679)], + ] }, + Figura { nombre: "Ophiuchus", paths: &[ + &[(-90.2434, -9.7736), (-93.0268, 2.7073), (-94.1319, 4.5673), (-96.2664, 12.5600), (-105.5829, 9.3750), (-112.2716, 1.9839), (-116.4136, -3.6943), (-115.4196, -4.6925), (-110.7103, -10.5671), (-102.4055, -15.7249)], + &[(-105.5829, 9.3750), (-110.7103, -10.5671), (-112.2151, -16.6127), (-113.2440, -18.4563), (-113.9742, -20.0373), (-113.6037, -23.4472)], + &[(-94.1319, 4.5673), (-102.4055, -15.7249), (-99.4976, -24.9995), (-98.1614, -29.8670)], + ] }, + Figura { nombre: "Orion", paths: &[ + &[(91.8930, 14.7685), (88.5958, 20.2762), (90.9799, 20.1385), (92.9850, 14.2088), (90.5958, 9.6473), (88.7929, 7.4071), (81.2828, 6.3497), (73.7239, 10.1508)], + &[(74.6371, 1.7140), (73.5629, 2.4407), (72.8015, 5.6051), (72.4600, 6.9613), (72.6530, 8.9002), (73.7239, 10.1508), (74.0928, 13.5145), (76.1423, 15.4041), (77.4248, 15.5972)], + &[(78.6345, -8.2016), (81.1192, -2.3971), (83.0017, -0.2991), (81.2828, 6.3497), (83.7845, 9.9342), (88.7929, 7.4071), (85.1897, -1.9426), (86.9391, -9.6696)], + &[(85.1897, -1.9426), (84.0534, -1.2019), (83.0017, -0.2991)], + ] }, + Figura { nombre: "Pavo", paths: &[ + &[(-53.5881, -56.7351), (-48.7604, -66.2032), (-57.8183, -66.1821), (-76.9457, -62.1876), (-84.1932, -61.4939), (-87.8549, -63.6686), (-93.5667, -64.7239), (-79.2411, -71.4281), (-59.8519, -72.9105), (-48.7604, -66.2032), (-38.3891, -65.3662)], + ] }, + Figura { nombre: "Pegasus", paths: &[ + &[(-27.5031, 33.1782), (-19.2494, 30.2212), (-14.0564, 28.0828), (2.0969, 29.0904), (3.3090, 15.1836), (-13.8098, 15.2053), (-18.3267, 12.1729), (-19.6345, 10.8314), (-27.4501, 6.1979), (-33.9535, 9.8750)], + &[(-13.8098, 15.2053), (-14.0564, 28.0828), (-17.4992, 24.6016), (-18.3672, 23.5657), (-28.2472, 25.3451), (-33.8386, 25.6450)], + ] }, + Figura { nombre: "Perseus", paths: &[ + &[(56.0797, 32.2882), (58.5330, 31.8836), (59.7413, 35.7910), (59.4635, 40.0102), (56.2985, 42.5785), (55.7313, 47.7876), (54.1224, 48.1926), (51.0807, 49.8612), (46.1991, 53.5064), (42.6742, 55.8955), (43.5644, 52.7625), (47.2667, 49.6133), (47.3740, 44.8575), (47.0422, 40.9556), (47.8224, 39.6116), (46.2941, 38.8403), (44.6903, 39.6627), (44.9162, 41.0329), (47.0422, 40.9556)], + &[(61.6460, 50.3513), (63.7244, 48.4093), (62.1654, 47.7125), (55.7313, 47.7876)], + &[(47.2667, 49.6133), (41.0499, 49.2284), (25.9152, 50.6887)], + ] }, + Figura { nombre: "Phoenix", paths: &[ + &[(6.5710, -42.3060), (16.5210, -46.7184), (22.0914, -43.3182), (22.8129, -49.0727), (17.0962, -55.2458), (16.5210, -46.7184), (2.3527, -45.7474), (6.5710, -42.3060)], + ] }, + Figura { nombre: "Pictor", paths: &[ + &[(102.0477, -61.9414), (87.4569, -56.1667), (86.8212, -51.0665)], + ] }, + Figura { nombre: "Pisces", paths: &[ + &[(18.4373, 24.5837), (17.9152, 30.0896), (19.8666, 27.2641), (18.4373, 24.5837), (17.8634, 21.0347), (22.8709, 15.3458), (26.3485, 9.1577), (30.5118, 2.7638), (28.3890, 3.1875), (25.3579, 5.4876), (22.5463, 6.1438), (18.4329, 7.5754), (15.7359, 7.8901), (12.1706, 7.5851), (-0.1721, 6.8633), (-5.0123, 5.6263), (-8.0079, 6.3790), (-9.9142, 5.3813), (-10.7086, 3.2823), (-8.2669, 1.2556), (-4.4883, 1.7800), (-3.4020, 3.4868), (-5.0123, 5.6263)], + &[(-10.7086, 3.2823), (-14.0308, 3.8200)], + ] }, + Figura { nombre: "Piscis Austrinus", paths: &[ + &[(-19.8361, -27.0436), (-15.5873, -29.6222), (-16.0129, -32.5396), (-16.8686, -32.8755), (-22.1236, -32.3461), (-27.9041, -32.9885), (-33.7633, -33.0258), (-33.0660, -30.8983), (-27.9041, -32.9885), (-19.8361, -27.0436)], + ] }, + Figura { nombre: "Puppis", paths: &[ + &[(99.4403, -43.1959), (109.2857, -37.0975), (113.8454, -28.3693), (114.7078, -26.8038), (117.3236, -24.8598), (119.2147, -22.8801), (121.8860, -24.3043), (120.8960, -40.0031), (122.3831, -47.3366)], + &[(117.3236, -24.8598), (117.0215, -25.9372), (115.9520, -28.9548), (113.8454, -28.3693)], + ] }, + Figura { nombre: "Pyxis", paths: &[ + &[(120.8960, -40.0031), (130.0256, -35.3084), (130.8981, -33.1864), (132.6330, -27.7098)], + ] }, + Figura { nombre: "Reticulum", paths: &[ + &[(63.6062, -62.4739), (64.1210, -59.3022), (59.6865, -61.4002), (56.0499, -64.8069), (63.6062, -62.4739)], + ] }, + Figura { nombre: "Sagitta", paths: &[ + &[(-64.9759, 18.0139), (-63.1531, 18.5343), (-60.3107, 19.4921)], + &[(-64.7378, 17.4760), (-63.1531, 18.5343)], + ] }, + Figura { nombre: "Sagittarius", paths: &[ + &[(-85.5932, -36.7617), (-83.9570, -34.3846), (-84.7515, -29.8281), (-83.0073, -25.4217), (-86.5591, -21.0588)], + &[(-69.3404, -44.4590), (-69.0284, -40.6159), (-74.3470, -29.8801), (-78.5859, -26.9908), (-83.0073, -25.4217)], + &[(-61.1846, -41.8683), (-60.0659, -35.2763), (-61.0402, -26.2995), (-65.8232, -24.8836), (-68.6813, -24.5086), (-71.1149, -25.2567), (-76.1836, -26.2967), (-78.5859, -26.9908), (-84.7515, -29.8281), (-88.5480, -30.4241), (-83.9570, -34.3846), (-74.3470, -29.8801), (-73.2650, -27.6704), (-76.1836, -26.2967), (-73.8292, -21.7415), (-72.5590, -21.0236), (-70.5913, -18.9529), (-69.5818, -17.8472), (-69.5682, -15.9550)], + &[(-73.8292, -21.7415), (-75.5675, -21.1067), (-76.4576, -22.7448), (-76.1836, -26.2967)], + ] }, + Figura { nombre: "Scorpius", paths: &[ + &[(-120.2870, -26.1141), (-119.9166, -22.6217), (-118.6407, -19.8055)], + &[(-119.9166, -22.6217), (-114.7028, -25.5928), (-112.6481, -26.4320), (-111.0294, -28.2160), (-107.4591, -34.2932), (-107.0324, -38.0474), (-106.3541, -42.3613), (-101.9617, -43.2392), (-95.6703, -42.9978), (-93.1038, -40.1270), (-94.3780, -39.0300), (-96.5978, -37.1038)], + ] }, + Figura { nombre: "Sculptor", paths: &[ + &[(14.6515, -29.3574), (-2.7686, -28.1303), (-10.2940, -32.5320), (-6.7573, -37.8183)], + ] }, + Figura { nombre: "Scutum", paths: &[ + &[(-81.1982, -8.2441), (-78.2064, -4.7479), (-79.4316, -9.0525), (-82.7006, -14.5658), (-81.1982, -8.2441)], + ] }, + Figura { nombre: "Serpens Cauda", paths: &[ + &[(-123.4531, 15.4218), (-124.6123, 19.6704), (-122.8151, 18.1416), (-120.8867, 15.6616), (-123.4531, 15.4218), (-126.2994, 10.5389), (-123.9330, 6.4256), (-122.2960, 4.4777), (-116.4136, -3.6943)], + ] }, + Figura { nombre: "Serpens Cauda", paths: &[ + &[(-102.4055, -15.7249), (-95.6033, -15.3986), (-90.2434, -9.7736), (-89.2295, -8.1803), (-84.6725, -2.8988), (-75.9451, 4.2036)], + ] }, + Figura { nombre: "Sextans", paths: &[ + &[(151.9845, -0.3716), (148.1268, -8.1050), (157.3696, -2.7391), (157.5728, -0.6370)], + ] }, + Figura { nombre: "Taurus", paths: &[ + &[(84.4112, 21.1425), (68.9802, 16.5093), (67.1656, 15.8709), (64.9483, 15.6276), (65.7337, 17.5425), (67.1542, 19.1804), (81.5730, 28.6075)], + &[(64.9483, 15.6276), (60.1701, 12.4903), (51.7923, 9.7327), (60.7891, 5.9893)], + &[(51.7923, 9.7327), (51.2033, 9.0289), (54.2183, 0.4017)], + ] }, + Figura { nombre: "Telescopium", paths: &[ + &[(-87.1927, -45.9544), (-83.2566, -45.9685), (-82.7923, -49.0706)], + ] }, + Figura { nombre: "Triangulum", paths: &[ + &[(28.2704, 29.5788), (32.3859, 34.9873), (34.3286, 33.8472), (28.2704, 29.5788)], + ] }, + Figura { nombre: "Triangulum Australe", paths: &[ + &[(-107.8338, -69.0277), (-121.2143, -63.4307), (-130.2726, -68.6795), (-107.8338, -69.0277)], + ] }, + Figura { nombre: "Tucana", paths: &[ + &[(-25.3746, -60.2596), (-10.6426, -58.2357), (7.8861, -62.9582), (5.0178, -64.8748), (-0.0209, -65.5771), (-23.1668, -64.9664), (-25.3746, -60.2596)], + ] }, + Figura { nombre: "Ursa Major", paths: &[ + &[(-176.1435, 57.0326), (165.9320, 61.7510), (165.4603, 56.3824), (178.4577, 53.6948), (-176.1435, 57.0326), (-166.4927, 55.9598), (-159.0186, 54.9254), (-153.1148, 49.3133)], + &[(178.4577, 53.6948), (176.5126, 47.7794), (169.6197, 33.0943), (169.5468, 31.5308)], + &[(176.5126, 47.7794), (167.4159, 44.4985), (155.5823, 41.4995)], + &[(167.4159, 44.4985), (154.2741, 42.9144)], + &[(165.9320, 61.7510), (142.8821, 63.0619), (127.5661, 60.7182), (147.7473, 59.0387), (165.4603, 56.3824)], + &[(165.4603, 56.3824), (148.0265, 54.0643), (143.2143, 51.6773), (134.8019, 48.0418)], + &[(135.9064, 47.1565), (143.2143, 51.6773)], + ] }, + Figura { nombre: "Ursa Minor", paths: &[ + &[(-123.9853, 77.7945), (-115.6238, 75.7553), (-129.8179, 71.8340), (-137.3236, 74.1555), (-123.9853, 77.7945), (-108.5073, 82.0373), (-96.9458, 86.5865), (37.9545, 89.2641)], + ] }, + Figura { nombre: "Vela", paths: &[ + &[(131.1759, -54.7088), (140.5284, -55.0107), (149.2156, -54.5678), (161.6924, -49.4203), (153.6840, -42.1219), (142.6750, -40.4668), (136.9990, -43.4326), (122.3831, -47.3366)], + ] }, + Figura { nombre: "Virgo", paths: &[ + &[(176.4648, 6.5294), (177.6738, 1.7647), (-175.0235, -0.6668), (-169.5848, -1.4494), (-162.5125, -5.5390), (-158.7018, -11.1613), (-145.9964, -6.0005), (-139.2349, -5.6582)], + &[(-164.4558, 10.9592), (-166.0991, 3.3975), (-169.5848, -1.4494)], + &[(-162.5125, -5.5390), (-156.3267, -0.5958), (-149.5884, 1.5445), (-138.4378, 1.8929)], + ] }, + Figura { nombre: "Volans", paths: &[ + &[(135.6116, -66.3961), (126.4341, -66.1369), (121.9825, -68.6171), (109.2076, -67.9572), (107.1869, -70.4989), (121.9825, -68.6171), (135.6116, -66.3961)], + ] }, + Figura { nombre: "Vulpecula", paths: &[ + &[(-70.9457, 21.3904), (-67.8236, 24.6649), (-61.6346, 24.0796), (-59.7248, 27.7536), (-56.0578, 27.8142)], + ] }, +]; diff --git a/crates/modules/cosmobiologia/cosmobiologia-render/src/lib.rs b/crates/modules/cosmobiologia/cosmobiologia-render/src/lib.rs index 54d5744..1fe4a4f 100644 --- a/crates/modules/cosmobiologia/cosmobiologia-render/src/lib.rs +++ b/crates/modules/cosmobiologia/cosmobiologia-render/src/lib.rs @@ -30,6 +30,7 @@ use serde::{Deserialize, Serialize}; pub use cosmobiologia_model::{Chart, ChartId, ChartKind}; +mod constellations_data; pub mod draw; pub mod gr; pub mod harmonic; diff --git a/crates/modules/cosmobiologia/cosmobiologia-render/src/sphere3d.rs b/crates/modules/cosmobiologia/cosmobiologia-render/src/sphere3d.rs index ee1acfd..d7c6b5f 100644 --- a/crates/modules/cosmobiologia/cosmobiologia-render/src/sphere3d.rs +++ b/crates/modules/cosmobiologia/cosmobiologia-render/src/sphere3d.rs @@ -92,6 +92,8 @@ pub struct SphereOpts { /// La Tierra interior — un globo pequeño, transparente, con los /// continentes esquemáticos y el observador marcado en su lugar. pub show_earth: bool, + /// Las figuras de las 88 constelaciones (catálogo d3-celestial). + pub show_constellations: bool, } impl Default for SphereOpts { @@ -107,6 +109,7 @@ impl Default for SphereOpts { show_horizon: true, show_sky: true, show_earth: true, + show_constellations: true, } } } @@ -376,6 +379,90 @@ fn add_loop( } } +/// Proyecta una polilínea ABIERTA y empuja un `Line` por segmento. +fn add_path( + items: &mut Vec<(f32, DrawCommand)>, + proj: &Projector, + pts: &[Vec3], + color: Rgba, + width: f32, +) { + for i in 0..pts.len().saturating_sub(1) { + let a = proj.project(pts[i]); + let b = proj.project(pts[i + 1]); + let d = (a.depth + b.depth) * 0.5; + items.push(( + d, + DrawCommand::Line { + x1: a.x, + y1: a.y, + x2: b.x, + y2: b.y, + color: dim(color, d), + width, + dash: None, + }, + )); + } +} + +/// Dibuja las figuras de las 88 constelaciones: cada trazo une estrellas +/// reales del catálogo (un punto por vértice), y el nombre va en el +/// centroide. Capa tenue — referencia, no protagonista. +fn add_constellations( + items: &mut Vec<(f32, DrawCommand)>, + proj: &Projector, + eps: f32, + size: f32, + pal: &Palette, +) { + let line_col = pal.fg_muted.with_alpha(0.42); + let star = Rgba::opaque(0.92, 0.95, 1.0); + for fig in crate::constellations_data::FIGURAS { + let (mut sx, mut sy, mut sz, mut n) = (0.0_f32, 0.0_f32, 0.0_f32, 0.0_f32); + for path in fig.paths { + let pts: Vec = path + .iter() + .map(|&(ra, dec)| rot_x(equatorial_dir(ra, dec), eps)) + .collect(); + add_path(items, proj, &pts, line_col, 0.7); + for v in &pts { + sx += v.x; + sy += v.y; + sz += v.z; + n += 1.0; + let p = proj.project(*v); + items.push(( + p.depth - 0.01, + DrawCommand::Circle { + cx: p.x, + cy: p.y, + r: size * 0.0017, + stroke: None, + fill: Some(star.with_alpha(0.70 * depth_alpha(p.depth))), + stroke_w: 0.0, + }, + )); + } + } + if n > 0.0 { + let c = Vec3::new(sx / n, sy / n, sz / n).normalized(); + let lp = proj.project(c); + items.push(( + lp.depth + 0.001, + DrawCommand::Text { + x: lp.x, + y: lp.y, + content: fig.nombre.into(), + color: pal.fg_muted.with_alpha(0.42 * depth_alpha(lp.depth)), + size: size * 0.0135, + anchor: TextAnchor::Middle, + }, + )); + } + } +} + /// Los `n` puntos de un círculo máximo perpendicular a `normal`. fn great_circle_perp(normal: Vec3, n: usize) -> Vec { let z = normal.normalized(); @@ -813,6 +900,11 @@ pub fn compose_sphere( add_starfield(&mut items, &proj, size, eps); } + // --- Figuras de las constelaciones --- + if opts.show_constellations { + add_constellations(&mut items, &proj, eps, size, pal); + } + // --- Rejilla: meridianos + paralelos de la eclíptica --- if opts.show_grid { let grid = pal.fg_muted.with_alpha(0.16); @@ -1231,7 +1323,12 @@ mod tests { #[test] fn compose_sphere_emite_esqueleto_y_cuerpos() { - let cmds = compose_sphere(&modelo_demo(), &SphereView::default(), &SphereOpts::default()); + // Sin constelaciones, para contar solo el esqueleto base. + let cmds = compose_sphere( + &modelo_demo(), + &SphereView::default(), + &SphereOpts { show_constellations: false, ..Default::default() }, + ); assert!(!cmds.is_empty(), "la esfera produce comandos"); let lineas = cmds.iter().filter(|c| matches!(c, DrawCommand::Line { .. })).count(); let textos = cmds.iter().filter(|c| matches!(c, DrawCommand::Text { .. })).count(); @@ -1241,6 +1338,30 @@ mod tests { assert_eq!(textos, 22, "glifos de signos, ángulos, polos y cuerpos: {textos}"); } + #[test] + fn las_constelaciones_dibujan_sus_figuras() { + assert!( + crate::constellations_data::FIGURAS.len() > 80, + "el catálogo trae las 88 constelaciones" + ); + let modelo = modelo_demo(); + let lineas = |c: &[DrawCommand]| { + c.iter().filter(|d| matches!(d, DrawCommand::Line { .. })).count() + }; + let con = compose_sphere(&modelo, &SphereView::default(), &SphereOpts::default()); + let sin = compose_sphere( + &modelo, + &SphereView::default(), + &SphereOpts { show_constellations: false, ..Default::default() }, + ); + assert!( + lineas(&con) > lineas(&sin) + 500, + "las figuras agregan cientos de trazos: {} vs {}", + lineas(&con), + lineas(&sin), + ); + } + #[test] fn el_cenit_esta_a_la_colatitud_del_polo_celeste() { let eps = OBLICUIDAD_DEG.to_radians();