ray

Owner: IIIlllIIIllI URL: git@github.com:nyangkosense/ray.git

missile test

Commit 2fa161eb4b6c72add07804ad6a6956ed6d487c7d by SM <seb.michalk@gmail.com> on 2025-06-30 11:16:52 +0200
diff --git a/Makefile b/Makefile
index 570ac99..f28479a 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ LDFLAGS += $(LIBS)
 LDFLAGS += -lopengl32 -lgdi32 -lm
 
 # Source files
-SOURCES = probe.cpp
+SOURCES = probe.cpp missile_guidance.cpp
 
 # Object files
 OBJECTS = $(SOURCES:.cpp=.o)
diff --git a/build/JTACCoords/win_x64/JTACCoords.xpl b/build/JTACCoords/win_x64/JTACCoords.xpl
deleted file mode 100755
index 2edc039..0000000
Binary files a/build/JTACCoords/win_x64/JTACCoords.xpl and /dev/null differ
diff --git a/missile_guidance.cpp b/missile_guidance.cpp
new file mode 100644
index 0000000..01ee942
--- /dev/null
+++ b/missile_guidance.cpp
@@ -0,0 +1,422 @@
+#include "XPLMDataAccess.h"
+#include "XPLMUtilities.h"
+#include "XPLMProcessing.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define DEG_TO_RAD (M_PI / 180.0)
+#define RAD_TO_DEG (180.0 / M_PI)
+
+// Missile guidance data refs
+static XPLMDataRef gMissileX[25];
+static XPLMDataRef gMissileY[25];
+static XPLMDataRef gMissileZ[25];
+static XPLMDataRef gMissileVX[25];
+static XPLMDataRef gMissileVY[25];
+static XPLMDataRef gMissileVZ[25];
+static XPLMDataRef gMissileQ1[25]; // Quaternion components
+static XPLMDataRef gMissileQ2[25];
+static XPLMDataRef gMissileQ3[25];
+static XPLMDataRef gMissileQ4[25];
+static XPLMDataRef gMissileThrustRat[25];
+static XPLMDataRef gMissileTargetLat[25];
+static XPLMDataRef gMissileTargetLon[25];
+static XPLMDataRef gMissileTargetH[25];
+static XPLMDataRef gMissileType[25];
+static XPLMDataRef gWeaponCount;
+
+// Aircraft data refs
+static XPLMDataRef gPlaneLatitude;
+static XPLMDataRef gPlaneLongitude;
+static XPLMDataRef gPlaneElevation;
+
+// Target coordinates from JTAC system
+struct TargetCoords {
+    double latitude;
+    double longitude;
+    double elevation;
+    float localX, localY, localZ;
+    bool valid;
+};
+
+static TargetCoords gGuidanceTarget = {0};
+static bool gGuidanceActive = false;
+static int gActiveMissileIndex = -1;
+
+// Quaternion utility functions
+void NormalizeQuaternion(float* q1, float* q2, float* q3, float* q4) {
+    float magnitude = sqrt(*q1 * *q1 + *q2 * *q2 + *q3 * *q3 + *q4 * *q4);
+    if (magnitude > 0.0001f) {
+        *q1 /= magnitude;
+        *q2 /= magnitude;
+        *q3 /= magnitude;
+        *q4 /= magnitude;
+    }
+}
+
+void QuaternionFromDirectionVector(float dirX, float dirY, float dirZ, 
+                                   float* q1, float* q2, float* q3, float* q4) {
+    // Create quaternion that rotates missile to point in direction vector
+    // This is a simplified version - assumes missile forward is along Z axis
+    
+    // Normalize direction vector
+    float length = sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+    if (length < 0.0001f) return;
+    
+    dirX /= length;
+    dirY /= length;
+    dirZ /= length;
+    
+    // Calculate rotation from (0,0,1) to direction vector
+    float forwardZ = 1.0f;
+    float dot = dirZ; // dot product with (0,0,1)
+    
+    if (dot > 0.9999f) {
+        // Already pointing forward
+        *q1 = 1.0f; *q2 = 0.0f; *q3 = 0.0f; *q4 = 0.0f;
+        return;
+    }
+    
+    if (dot < -0.9999f) {
+        // Pointing backward - rotate 180 degrees around X axis
+        *q1 = 0.0f; *q2 = 1.0f; *q3 = 0.0f; *q4 = 0.0f;
+        return;
+    }
+    
+    // Cross product to get rotation axis
+    float axisX = 0.0f - dirY; // (0,0,1) x (dirX,dirY,dirZ)
+    float axisY = dirX - 0.0f;
+    float axisZ = 0.0f - 0.0f;
+    
+    float axisLength = sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ);
+    if (axisLength > 0.0001f) {
+        axisX /= axisLength;
+        axisY /= axisLength;
+        axisZ /= axisLength;
+    }
+    
+    float angle = acos(dot);
+    float sinHalfAngle = sin(angle * 0.5f);
+    float cosHalfAngle = cos(angle * 0.5f);
+    
+    *q1 = cosHalfAngle;
+    *q2 = axisX * sinHalfAngle;
+    *q3 = axisY * sinHalfAngle;
+    *q4 = axisZ * sinHalfAngle;
+    
+    NormalizeQuaternion(q1, q2, q3, q4);
+}
+
+// Flight callback
+float MissileGuidanceCallback(float inElapsedSinceLastCall, float inElapsedTimeSinceLastFlightLoop, 
+                             int inCounter, void* inRefcon);
+
+// Initialize missile guidance system
+bool InitializeMissileGuidance() {
+    // Get weapon count
+    gWeaponCount = XPLMFindDataRef("sim/weapons/weapon_count");
+    if (!gWeaponCount) {
+        XPLMDebugString("Missile Guidance: Could not find weapon_count dataref\n");
+        return false;
+    }
+    
+    // Initialize missile data refs for all 25 possible weapons
+    for (int i = 0; i < 25; i++) {
+        char datarefName[256];
+        
+        // Position data refs
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/x[%d]", i);
+        gMissileX[i] = XPLMFindDataRef(datarefName);
+        
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/y[%d]", i);
+        gMissileY[i] = XPLMFindDataRef(datarefName);
+        
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/z[%d]", i);
+        gMissileZ[i] = XPLMFindDataRef(datarefName);
+        
+        // Velocity data refs
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/vx[%d]", i);
+        gMissileVX[i] = XPLMFindDataRef(datarefName);
+        
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/vy[%d]", i);
+        gMissileVY[i] = XPLMFindDataRef(datarefName);
+        
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/vz[%d]", i);
+        gMissileVZ[i] = XPLMFindDataRef(datarefName);
+        
+        // Quaternion orientation data refs
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/q1[%d]", i);
+        gMissileQ1[i] = XPLMFindDataRef(datarefName);
+        
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/q2[%d]", i);
+        gMissileQ2[i] = XPLMFindDataRef(datarefName);
+        
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/q3[%d]", i);
+        gMissileQ3[i] = XPLMFindDataRef(datarefName);
+        
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/q4[%d]", i);
+        gMissileQ4[i] = XPLMFindDataRef(datarefName);
+        
+        // Thrust control
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/shell/thrust_rat[%d]", i);
+        gMissileThrustRat[i] = XPLMFindDataRef(datarefName);
+        
+        // Target coordinates
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/targ_lat[%d]", i);
+        gMissileTargetLat[i] = XPLMFindDataRef(datarefName);
+        
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/targ_lon[%d]", i);
+        gMissileTargetLon[i] = XPLMFindDataRef(datarefName);
+        
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/targ_h[%d]", i);
+        gMissileTargetH[i] = XPLMFindDataRef(datarefName);
+        
+        // Weapon type
+        snprintf(datarefName, sizeof(datarefName), "sim/weapons/type[%d]", i);
+        gMissileType[i] = XPLMFindDataRef(datarefName);
+    }
+    
+    // Aircraft position
+    gPlaneLatitude = XPLMFindDataRef("sim/flightmodel/position/latitude");
+    gPlaneLongitude = XPLMFindDataRef("sim/flightmodel/position/longitude");
+    gPlaneElevation = XPLMFindDataRef("sim/flightmodel/position/elevation");
+    
+    // Register flight loop callback for guidance
+    XPLMRegisterFlightLoopCallback(MissileGuidanceCallback, 0.1f, NULL);
+    
+    XPLMDebugString("Missile Guidance: Initialized successfully\n");
+    return true;
+}
+
+// Shutdown missile guidance system
+void ShutdownMissileGuidance() {
+    XPLMUnregisterFlightLoopCallback(MissileGuidanceCallback, NULL);
+}
+
+// Set target coordinates for missile guidance
+void SetMissileTarget(const TargetCoords& target) {
+    gGuidanceTarget = target;
+    gGuidanceActive = target.valid;
+    
+    if (gGuidanceActive) {
+        char buffer[256];
+        snprintf(buffer, sizeof(buffer), 
+                "Missile Guidance: Target set to %.6f, %.6f, %.0fm\n", 
+                target.latitude, target.longitude, target.elevation);
+        XPLMDebugString(buffer);
+    }
+}
+
+// Find the next available missile to guide
+int FindAvailableMissile() {
+    if (!gWeaponCount) return -1;
+    
+    int weaponCount = XPLMGetDatai(gWeaponCount);
+    
+    for (int i = 0; i < weaponCount && i < 25; i++) {
+        if (gMissileType[i] && gMissileX[i] && gMissileY[i] && gMissileZ[i]) {
+            int weaponType = XPLMGetDatai(gMissileType[i]);
+            // Check if it's a missile type (you may need to adjust this based on X-Plane weapon types)
+            if (weaponType > 0) {
+                return i;
+            }
+        }
+    }
+    
+    return -1;
+}
+
+// Calculate proportional navigation guidance
+void CalculateProportionalNavigation(int missileIndex, float deltaTime) {
+    if (!gGuidanceTarget.valid || missileIndex < 0 || missileIndex >= 25) return;
+    
+    // Get missile current position
+    float missileX = XPLMGetDataf(gMissileX[missileIndex]);
+    float missileY = XPLMGetDataf(gMissileY[missileIndex]);
+    float missileZ = XPLMGetDataf(gMissileZ[missileIndex]);
+    
+    // Get missile current velocity
+    float missileVX = XPLMGetDataf(gMissileVX[missileIndex]);
+    float missileVY = XPLMGetDataf(gMissileVY[missileIndex]);
+    float missileVZ = XPLMGetDataf(gMissileVZ[missileIndex]);
+    
+    // Calculate relative position to target
+    float relativeX = gGuidanceTarget.localX - missileX;
+    float relativeY = gGuidanceTarget.localY - missileY;
+    float relativeZ = gGuidanceTarget.localZ - missileZ;
+    
+    // Calculate distance to target
+    float distance = sqrt(relativeX * relativeX + relativeY * relativeY + relativeZ * relativeZ);
+    
+    if (distance < 10.0f) {
+        // Close to target, reduce thrust
+        XPLMSetDataf(gMissileThrustRat[missileIndex], 0.1f);
+        return;
+    }
+    
+    // Normalize relative position vector (line of sight)
+    float losX = relativeX / distance;
+    float losY = relativeY / distance;
+    float losZ = relativeZ / distance;
+    
+    // Calculate missile speed
+    float speed = sqrt(missileVX * missileVX + missileVY * missileVY + missileVZ * missileVZ);
+    if (speed < 1.0f) speed = 1.0f; // Avoid division by zero
+    
+    // Calculate closing velocity
+    float closingVelocity = -(missileVX * losX + missileVY * losY + missileVZ * losZ);
+    
+    // Time to intercept
+    float timeToIntercept = distance / (closingVelocity > 0 ? closingVelocity : 1.0f);
+    
+    // Proportional navigation constant (typically 3-5)
+    float navigationConstant = 3.0f;
+    
+    // Calculate desired velocity direction
+    float desiredVX = losX;
+    float desiredVY = losY; 
+    float desiredVZ = losZ;
+    
+    // Apply proportional navigation correction
+    if (timeToIntercept > 0.1f) {
+        // Calculate angular velocity of line of sight
+        static float prevLosX = losX, prevLosY = losY, prevLosZ = losZ;
+        float angularVelX = (losX - prevLosX) / deltaTime;
+        float angularVelY = (losY - prevLosY) / deltaTime;
+        float angularVelZ = (losZ - prevLosZ) / deltaTime;
+        
+        // Apply proportional navigation
+        desiredVX += navigationConstant * speed * angularVelX;
+        desiredVY += navigationConstant * speed * angularVelY;
+        desiredVZ += navigationConstant * speed * angularVelZ;
+        
+        prevLosX = losX;
+        prevLosY = losY;
+        prevLosZ = losZ;
+    }
+    
+    // Normalize desired velocity
+    float desiredSpeed = sqrt(desiredVX * desiredVX + desiredVY * desiredVY + desiredVZ * desiredVZ);
+    if (desiredSpeed > 0.1f) {
+        desiredVX = (desiredVX / desiredSpeed) * speed;
+        desiredVY = (desiredVY / desiredSpeed) * speed;
+        desiredVZ = (desiredVZ / desiredSpeed) * speed;
+    }
+    
+    // Calculate velocity correction
+    float deltaVX = desiredVX - missileVX;
+    float deltaVY = desiredVY - missileVY;
+    float deltaVZ = desiredVZ - missileVZ;
+    
+    // Apply velocity correction (simple proportional control)
+    float correctionGain = 0.1f;
+    XPLMSetDataf(gMissileVX[missileIndex], missileVX + deltaVX * correctionGain);
+    XPLMSetDataf(gMissileVY[missileIndex], missileVY + deltaVY * correctionGain);
+    XPLMSetDataf(gMissileVZ[missileIndex], missileVZ + deltaVZ * correctionGain);
+    
+    // Update missile orientation quaternion to point toward target
+    if (gMissileQ1[missileIndex] && gMissileQ2[missileIndex] && 
+        gMissileQ3[missileIndex] && gMissileQ4[missileIndex]) {
+        
+        float q1, q2, q3, q4;
+        QuaternionFromDirectionVector(desiredVX, desiredVY, desiredVZ, &q1, &q2, &q3, &q4);
+        
+        // Smoothly interpolate toward desired orientation
+        float currentQ1 = XPLMGetDataf(gMissileQ1[missileIndex]);
+        float currentQ2 = XPLMGetDataf(gMissileQ2[missileIndex]);
+        float currentQ3 = XPLMGetDataf(gMissileQ3[missileIndex]);
+        float currentQ4 = XPLMGetDataf(gMissileQ4[missileIndex]);
+        
+        float orientationGain = 0.2f; // Smooth orientation changes
+        float newQ1 = currentQ1 + (q1 - currentQ1) * orientationGain;
+        float newQ2 = currentQ2 + (q2 - currentQ2) * orientationGain;
+        float newQ3 = currentQ3 + (q3 - currentQ3) * orientationGain;
+        float newQ4 = currentQ4 + (q4 - currentQ4) * orientationGain;
+        
+        // Normalize and set new orientation
+        NormalizeQuaternion(&newQ1, &newQ2, &newQ3, &newQ4);
+        XPLMSetDataf(gMissileQ1[missileIndex], newQ1);
+        XPLMSetDataf(gMissileQ2[missileIndex], newQ2);
+        XPLMSetDataf(gMissileQ3[missileIndex], newQ3);
+        XPLMSetDataf(gMissileQ4[missileIndex], newQ4);
+    }
+    
+    // Set thrust based on distance
+    float thrustRatio = 1.0f;
+    if (distance < 1000.0f) {
+        thrustRatio = 0.5f; // Reduce thrust when close
+    } else if (distance > 5000.0f) {
+        thrustRatio = 1.0f; // Full thrust when far
+    } else {
+        thrustRatio = 0.5f + 0.5f * (distance - 1000.0f) / 4000.0f;
+    }
+    
+    XPLMSetDataf(gMissileThrustRat[missileIndex], thrustRatio);
+}
+
+// Flight loop callback for missile guidance
+float MissileGuidanceCallback(float inElapsedSinceLastCall, float inElapsedTimeSinceLastFlightLoop, 
+                             int inCounter, void* inRefcon) {
+    
+    if (!gGuidanceActive) {
+        return 0.1f; // Call again in 0.1 seconds
+    }
+    
+    // Find active missile if we don't have one
+    if (gActiveMissileIndex < 0) {
+        gActiveMissileIndex = FindAvailableMissile();
+        if (gActiveMissileIndex < 0) {
+            return 0.1f; // No missiles available
+        }
+        
+        // Set target coordinates in weapon system
+        if (gMissileTargetLat[gActiveMissileIndex] && gMissileTargetLon[gActiveMissileIndex] && gMissileTargetH[gActiveMissileIndex]) {
+            XPLMSetDataf(gMissileTargetLat[gActiveMissileIndex], (float)gGuidanceTarget.latitude);
+            XPLMSetDataf(gMissileTargetLon[gActiveMissileIndex], (float)gGuidanceTarget.longitude);
+            XPLMSetDataf(gMissileTargetH[gActiveMissileIndex], (float)gGuidanceTarget.elevation);
+        }
+        
+        char buffer[128];
+        snprintf(buffer, sizeof(buffer), "Missile Guidance: Guiding missile %d to target\n", gActiveMissileIndex);
+        XPLMDebugString(buffer);
+    }
+    
+    // Apply proportional navigation guidance
+    CalculateProportionalNavigation(gActiveMissileIndex, inElapsedSinceLastCall);
+    
+    return 0.05f; // Call again in 0.05 seconds for responsive guidance
+}
+
+// External interface for JTAC system
+extern "C" {
+    bool InitMissileGuidance() {
+        return InitializeMissileGuidance();
+    }
+    
+    
+    void SetJTACTarget(double latitude, double longitude, double elevation, 
+                       float localX, float localY, float localZ) {
+        TargetCoords target;
+        target.latitude = latitude;
+        target.longitude = longitude;
+        target.elevation = elevation;
+        target.localX = localX;
+        target.localY = localY;
+        target.localZ = localZ;
+        target.valid = true;
+        
+        SetMissileTarget(target);
+        gActiveMissileIndex = -1; // Reset to find new missile
+    }
+    
+    void ClearMissileTarget() {
+        gGuidanceActive = false;
+        gActiveMissileIndex = -1;
+        XPLMDebugString("Missile Guidance: Target cleared\n");
+    }
+}
\ No newline at end of file
diff --git a/missile_guidance.h b/missile_guidance.h
new file mode 100644
index 0000000..fbe9d9a
--- /dev/null
+++ b/missile_guidance.h
@@ -0,0 +1,25 @@
+#ifndef MISSILE_GUIDANCE_H
+#define MISSILE_GUIDANCE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Initialize missile guidance system
+bool InitMissileGuidance();
+
+// Shutdown missile guidance system
+void ShutdownMissileGuidance();
+
+// Set target from JTAC system
+void SetJTACTarget(double latitude, double longitude, double elevation, 
+                   float localX, float localY, float localZ);
+
+// Clear current missile target
+void ClearMissileTarget();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MISSILE_GUIDANCE_H
\ No newline at end of file
diff --git a/missile_guidance.o b/missile_guidance.o
new file mode 100644
index 0000000..ad810d4
Binary files /dev/null and b/missile_guidance.o differ
diff --git a/probe.cpp b/probe.cpp
index ca7dbc6..3311fa1 100644
--- a/probe.cpp
+++ b/probe.cpp
@@ -9,6 +9,7 @@
 #include "XPLMPlugin.h"
 #include "XPLMDisplay.h"
 #include "XPLMProcessing.h"
+#include "missile_guidance.h"
 
 #ifndef M_PI
 #define M_PI 3.14159265358979323846
@@ -37,9 +38,11 @@ static XPLMDataRef gViewPitch = NULL;
 
 // Hotkey handling
 static XPLMHotKeyID gLaserHotkey = NULL;
+static XPLMHotKeyID gClearTargetHotkey = NULL;
 
 // Function declarations
 void LaserDesignationHotkey(void* refcon);
+void ClearTargetHotkey(void* refcon);
 
 // Terrain probe handle
 static XPLMProbeRef gTerrainProbe = NULL;
@@ -88,13 +91,25 @@ PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc) {
     // Register hotkey for laser designation (Ctrl+L)
     gLaserHotkey = XPLMRegisterHotKey(XPLM_VK_L, xplm_DownFlag | xplm_ControlFlag, "Laser Target Designation", LaserDesignationHotkey, NULL);
     
+    // Register hotkey for clearing target (Ctrl+C)
+    gClearTargetHotkey = XPLMRegisterHotKey(XPLM_VK_C, xplm_DownFlag | xplm_ControlFlag, "Clear Missile Target", ClearTargetHotkey, NULL);
+    
+    // Initialize missile guidance system
+    if (!InitMissileGuidance()) {
+        XPLMDebugString("JTAC: Warning - Missile guidance system failed to initialize\n");
+    }
+    
     return 1;
 }
 
 PLUGIN_API void XPluginStop(void) {
+    ShutdownMissileGuidance();
     if (gLaserHotkey) {
         XPLMUnregisterHotKey(gLaserHotkey);
     }
+    if (gClearTargetHotkey) {
+        XPLMUnregisterHotKey(gClearTargetHotkey);
+    }
     if (gTerrainProbe) {
         XPLMDestroyProbe(gTerrainProbe);
     }
@@ -375,6 +390,10 @@ void LaserDesignationHotkey(void* refcon) {
         // Perform laser designation at screen center
         if (DesignateLaser(centerX, centerY, &gLastTarget)) {
             XPLMDebugString("JTAC: Target designated successfully at crosshair\n");
+            
+            // Send target to missile guidance system
+            SetJTACTarget(gLastTarget.latitude, gLastTarget.longitude, gLastTarget.elevation,
+                         gLastTarget.localX, gLastTarget.localY, gLastTarget.localZ);
         } else {
             XPLMDebugString("JTAC: No terrain intersection found at crosshair\n");
         }
@@ -383,6 +402,12 @@ void LaserDesignationHotkey(void* refcon) {
     }
 }
 
+// Clear target hotkey callback (Ctrl+C)
+void ClearTargetHotkey(void* refcon) {
+    ClearMissileTarget();
+    XPLMDebugString("JTAC: Missile target cleared\n");
+}
+
 // Display window draw function
 void DrawWindow(XPLMWindowID inWindowID, void* inRefcon) {
     int left, top, right, bottom;
@@ -447,6 +472,9 @@ void DrawWindow(XPLMWindowID inWindowID, void* inRefcon) {
     snprintf(buffer, sizeof(buffer), "Press Ctrl+L to designate target at crosshair");
     float gray[] = {0.78f, 0.78f, 0.78f};
     XPLMDrawString(gray, left + 10, top - 20 - (line++ * 15), buffer, NULL, xplmFont_Proportional);
+    
+    snprintf(buffer, sizeof(buffer), "Press Ctrl+C to clear missile target");
+    XPLMDrawString(gray, left + 10, top - 20 - (line++ * 15), buffer, NULL, xplmFont_Proportional);
 }
 
 // Create window
diff --git a/probe.o b/probe.o
index 553d250..e375ee4 100644
Binary files a/probe.o and b/probe.o differ