PHP script

Her er koden fremstillet med en dedikeret AI – Vo.dev -beregnet til udvikling af programmer :

Den var meget skarp . Bedre end de generelle.

<!DOCTYPE html>
<html lang="da">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CPA/TCPA Navigator</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .container {
            background: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        h1 {
            color: #2c3e50;
            text-align: center;
            margin-bottom: 30px;
        }
        .form-group {
            margin-bottom: 15px;
        }
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            color: #34495e;
        }
        input[type="number"] {
            width: 100%;
            padding: 10px;
            border: 2px solid #bdc3c7;
            border-radius: 5px;
            font-size: 16px;
        }
        input[type="number"]:focus {
            border-color: #3498db;
            outline: none;
        }
        button {
            background-color: #3498db;
            color: white;
            padding: 12px 30px;
            border: none;
            border-radius: 5px;
            font-size: 16px;
            cursor: pointer;
            width: 100%;
            margin-top: 20px;
        }
        button:hover {
            background-color: #2980b9;
        }
        .results {
            margin-top: 30px;
            padding: 15px;
            background-color: #ecf0f1;
            border-radius: 5px;
            font-size: 14px;
        }
        .results h2 {
            font-size: 16px;
            margin-bottom: 15px;
        }
        .result-item {
            margin-bottom: 8px;
            font-size: 14px;
        }
        .result-value {
            font-weight: bold;
            color: #e74c3c;
        }
        .two-column {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
        }
        .section-title {
            color: #2c3e50;
            font-size: 18px;
            margin-bottom: 15px;
            border-bottom: 2px solid #3498db;
            padding-bottom: 5px;
        }
        /* Added styles for compass diagram */
        .results-with-diagram {
            display: grid;
            grid-template-columns: 300px 1fr;
            gap: 30px;
            margin-top: 30px;
        }
        .compass-container {
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            text-align: center;
        }
        .compass-title {
            color: #2c3e50;
            font-size: 18px;
            margin-bottom: 15px;
            font-weight: bold;
        }
        .legend {
            margin-top: 15px;
            text-align: left;
            font-size: 12px;
        }
        .legend-item {
            margin-bottom: 5px;
            display: flex;
            align-items: center;
        }
        .legend-color {
            width: 20px;
            height: 3px;
            margin-right: 8px;
        }
        @media (max-width: 768px) {
            .results-with-diagram {
                grid-template-columns: 1fr;
            }
            .compass-container {
                order: -1;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>CPA/TCPA Navigator</h1>
        
        <form method="POST">
            <div class="two-column">
                <div>
                    <div class="section-title">Observation 1</div>
                    <div class="form-group">
                        <label for="bearing1">Pejling 1 (grader):</label>
                        <input type="number" id="bearing1" name="bearing1" step="0.1" value="<?php echo isset($_POST['bearing1']) ? $_POST['bearing1'] : ''; ?>" required>
                    </div>
                    <div class="form-group">
                        <label for="distance1">Afstand 1 (sømil):</label>
                        <input type="number" id="distance1" name="distance1" step="0.1" value="<?php echo isset($_POST['distance1']) ? $_POST['distance1'] : ''; ?>" required>
                    </div>
                </div>
                
                <div>
                    <div class="section-title">Observation 2</div>
                    <div class="form-group">
                        <label for="bearing2">Pejling 2 (grader):</label>
                        <input type="number" id="bearing2" name="bearing2" step="0.1" value="<?php echo isset($_POST['bearing2']) ? $_POST['bearing2'] : ''; ?>" required>
                    </div>
                    <div class="form-group">
                        <label for="distance2">Afstand 2 (sømil):</label>
                        <input type="number" id="distance2" name="distance2" step="0.1" value="<?php echo isset($_POST['distance2']) ? $_POST['distance2'] : ''; ?>" required>
                    </div>
                </div>
            </div>
            
            <div class="two-column">
                <div>
                    <div class="section-title">Eget Fartøj</div>
                    <div class="form-group">
                        <label for="own_speed">Egen fart (knob):</label>
                        <input type="number" id="own_speed" name="own_speed" step="0.1" value="<?php echo isset($_POST['own_speed']) ? $_POST['own_speed'] : ''; ?>" required>
                    </div>
                    <div class="form-group">
                        <label for="own_course">Egen kurs (grader):</label>
                        <input type="number" id="own_course" name="own_course" step="0.1" value="<?php echo isset($_POST['own_course']) ? $_POST['own_course'] : ''; ?>" required>
                    </div>
                </div>
                
                <div>
                    <div class="section-title">Tidsinterval</div>
                    <div class="form-group">
                        <label for="time_interval">Tidsinterval (minutter):</label>
                        <input type="number" id="time_interval" name="time_interval" step="0.1" value="<?php echo isset($_POST['time_interval']) ? $_POST['time_interval'] : ''; ?>" required>
                    </div>
                </div>
            </div>
            
            <button type="submit">Beregn CPA/TCPA</button>
        </form>

        <?php
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            // Hent input værdier
            $bearing1 = floatval($_POST['bearing1']);
            $distance1 = floatval($_POST['distance1']);
            $bearing2 = floatval($_POST['bearing2']);
            $distance2 = floatval($_POST['distance2']);
            $own_speed = floatval($_POST['own_speed']);
            $own_course = floatval($_POST['own_course']);
            $time_interval = floatval($_POST['time_interval']);
            
            // Konverter til radianer
            $bearing1_rad = deg2rad($bearing1);
            $bearing2_rad = deg2rad($bearing2);
            $own_course_rad = deg2rad($own_course);
            
            // Beregn positioner i kartesisk koordinatsystem
            $x1 = $distance1 * sin($bearing1_rad);
            $y1 = $distance1 * cos($bearing1_rad);
            $x2 = $distance2 * sin($bearing2_rad);
            $y2 = $distance2 * cos($bearing2_rad);
            
            // Beregn egen bevægelse i tidsintervallet
            $time_hours = $time_interval / 60;
            $own_distance = $own_speed * $time_hours;
            $own_dx = $own_distance * sin($own_course_rad);
            $own_dy = $own_distance * cos($own_course_rad);
            
            // Kompenser for egen bevægelse
            $target_dx = ($x2 - $x1) + $own_dx;
            $target_dy = ($y2 - $y1) + $own_dy;
            
            // Beregn målets fart og kurs
            $target_distance = sqrt($target_dx * $target_dx + $target_dy * $target_dy);
            $target_speed = $target_distance / $time_hours;
            $target_course = rad2deg(atan2($target_dx, $target_dy));
            if ($target_course < 0) $target_course += 360;
            
            // Beregn relativ kurs (målets kurs relativt til eget fartøj)
            $relative_course = $target_course - $own_course;
            if ($relative_course < 0) $relative_course += 360;
            if ($relative_course > 360) $relative_course -= 360;
            
            // Beregn relativ hastighed
            $rel_dx = $target_dx / $time_hours - $own_speed * sin($own_course_rad);
            $rel_dy = $target_dy / $time_hours - $own_speed * cos($own_course_rad);
            
            // Beregn CPA og TCPA
            $rel_speed = sqrt($rel_dx * $rel_dx + $rel_dy * $rel_dy);
            
            if ($rel_speed > 0.01) {
                // Dot product for at finde TCPA
                $dot_product = $x2 * $rel_dx + $y2 * $rel_dy;
                $tcpa_hours = -$dot_product / ($rel_speed * $rel_speed);
                $tcpa_minutes = $tcpa_hours * 60;
                
                // Beregn CPA position
                $cpa_x = $x2 + $rel_dx * $tcpa_hours;
                $cpa_y = $y2 + $rel_dy * $tcpa_hours;
                $cpa_distance = sqrt($cpa_x * $cpa_x + $cpa_y * $cpa_y);
            } else {
                $tcpa_minutes = 0;
                $cpa_distance = $distance2;
            }
            
            function generateCompassDiagram($own_course, $bearing1, $bearing2, $distance1, $distance2, $target_course, $relative_course, $cpa_distance, $tcpa_hours, $x2, $y2, $rel_dx, $rel_dy) {
                $svg = '<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">';
                
                // Distance rings (1, 2, 3, 4, 5 nautical miles)
                $max_distance = max($distance1, $distance2, 5); // Ensure at least 5 rings
                $scale = 200 / $max_distance; // Scale to fit in larger diagram
                
                for ($ring = 1; $ring <= 5; $ring++) {
                    $radius = $ring * $scale;
                    if ($radius <= 200) {
                        $svg .= '<circle cx="250" cy="250" r="' . $radius . '" fill="none" stroke="#ecf0f1" stroke-width="1" stroke-dasharray="2,2"/>';
                        // Distance labels
                        $svg .= '<text x="' . (250 + $radius - 10) . '" y="255" font-size="12" fill="#7f8c8d">' . $ring . 'nm</text>';
                    }
                }
                
                // Background circle
                $svg .= '<circle cx="250" cy="250" r="230" fill="none" stroke="#bdc3c7" stroke-width="2"/>';
                
                // Degree markings
                for ($i = 0; $i < 360; $i += 30) {
                    $x1 = 250 + 220 * sin(deg2rad($i));
                    $y1 = 250 - 220 * cos(deg2rad($i));
                    $x2 = 250 + 230 * sin(deg2rad($i));
                    $y2 = 250 - 230 * cos(deg2rad($i));
                    $svg .= '<line x1="' . $x1 . '" y1="' . $y1 . '" x2="' . $x2 . '" y2="' . $y2 . '" stroke="#7f8c8d" stroke-width="2"/>';
                    
                    // Degree labels
                    $label_x = 250 + 200 * sin(deg2rad($i));
                    $label_y = 250 - 200 * cos(deg2rad($i)) + 5;
                    $svg .= '<text x="' . $label_x . '" y="' . $label_y . '" text-anchor="middle" font-size="14" fill="#2c3e50">' . $i . '°</text>';
                }
                
                // Minor degree markings
                for ($i = 0; $i < 360; $i += 10) {
                    if ($i % 30 != 0) {
                        $x1 = 250 + 225 * sin(deg2rad($i));
                        $y1 = 250 - 225 * cos(deg2rad($i));
                        $x2 = 250 + 230 * sin(deg2rad($i));
                        $y2 = 250 - 230 * cos(deg2rad($i));
                        $svg .= '<line x1="' . $x1 . '" y1="' . $y1 . '" x2="' . $x2 . '" y2="' . $y2 . '" stroke="#bdc3c7" stroke-width="1"/>';
                    }
                }
                
                // North indicator
                $svg .= '<text x="250" y="30" text-anchor="middle" font-size="18" font-weight="bold" fill="#e74c3c">N</text>';
                
                $p1_x = 250 + $distance1 * $scale * sin(deg2rad($bearing1));
                $p1_y = 250 - $distance1 * $scale * cos(deg2rad($bearing1));
                $p2_x = 250 + $distance2 * $scale * sin(deg2rad($bearing2));
                $p2_y = 250 - $distance2 * $scale * cos(deg2rad($bearing2));
                
                // Calculate direction vector from P1 to P2
                $trajectory_dx = $p2_x - $p1_x;
                $trajectory_dy = $p2_y - $p1_y;
                $trajectory_length = sqrt($trajectory_dx * $trajectory_dx + $trajectory_dy * $trajectory_dy);
                
                if ($trajectory_length > 0) {
                    // Normalize direction vector
                    $trajectory_unit_x = $trajectory_dx / $trajectory_length;
                    $trajectory_unit_y = $trajectory_dy / $trajectory_length;
                    
                    // Extend line backwards from P1 and forwards from P2
                    $extend_distance = 300; // Extend line well beyond diagram
                    $line_start_x = $p1_x - $trajectory_unit_x * $extend_distance;
                    $line_start_y = $p1_y - $trajectory_unit_y * $extend_distance;
                    $line_end_x = $p2_x + $trajectory_unit_x * $extend_distance;
                    $line_end_y = $p2_y + $trajectory_unit_y * $extend_distance;
                    
                    // Draw extended trajectory line
                    $svg .= '<line x1="' . $line_start_x . '" y1="' . $line_start_y . '" x2="' . $line_end_x . '" y2="' . $line_end_y . '" stroke="#8e44ad" stroke-width="3" stroke-dasharray="10,5" opacity="0.8"/>';
                    
                    // Find the closest point on the trajectory line to the center (250, 250)
                    $center_x = 250;
                    $center_y = 250;
                    
                    // Vector from P1 to center
                    $p1_to_center_x = $center_x - $p1_x;
                    $p1_to_center_y = $center_y - $p1_y;
                    
                    // Project center onto trajectory line
                    $dot_product = $p1_to_center_x * $trajectory_unit_x + $p1_to_center_y * $trajectory_unit_y;
                    $closest_point_x = $p1_x + $dot_product * $trajectory_unit_x;
                    $closest_point_y = $p1_y + $dot_product * $trajectory_unit_y;
                    
                    // Draw perpendicular line from center to closest point on trajectory
                    $svg .= '<line x1="' . $center_x . '" y1="' . $center_y . '" x2="' . $closest_point_x . '" y2="' . $closest_point_y . '" stroke="#e67e22" stroke-width="4" stroke-dasharray="8,4"/>';
                    
                    // Mark the closest point on trajectory
                    $svg .= '<circle cx="' . $closest_point_x . '" cy="' . $closest_point_y . '" r="6" fill="#e67e22" stroke="#fff" stroke-width="2"/>';
                    
                    // Add label for geometric CPA
                    $label_offset_x = ($closest_point_x > $center_x) ? 15 : -25;
                    $label_offset_y = ($closest_point_y > $center_y) ? -10 : 20;
                    $svg .= '<text x="' . ($closest_point_x + $label_offset_x) . '" y="' . ($closest_point_y + $label_offset_y) . '" font-size="12" font-weight="bold" fill="#e67e22">CPA</text>';
                }
                
                // Own course (blue arrow)
                $own_x = 250 + 160 * sin(deg2rad($own_course));
                $own_y = 250 - 160 * cos(deg2rad($own_course));
                $svg .= '<line x1="250" y1="250" x2="' . $own_x . '" y2="' . $own_y . '" stroke="#3498db" stroke-width="5" marker-end="url(#arrowBlue)"/>';
                
                // Bearing 1 (green line) - scaled to actual distance
                $bear1_length = min($distance1 * $scale, 200);
                $bear1_x = 250 + $bear1_length * sin(deg2rad($bearing1));
                $bear1_y = 250 - $bear1_length * cos(deg2rad($bearing1));
                $svg .= '<line x1="250" y1="250" x2="' . $bear1_x . '" y2="' . $bear1_y . '" stroke="#27ae60" stroke-width="4"/>';
                $svg .= '<circle cx="' . $bear1_x . '" cy="' . $bear1_y . '" r="6" fill="#27ae60" stroke="#fff" stroke-width="2"/>';
                $svg .= '<text x="' . ($bear1_x + 10) . '" y="' . ($bear1_y - 10) . '" font-size="12" font-weight="bold" fill="#27ae60">P1</text>';
                
                // Bearing 2 (orange line) - scaled to actual distance
                $bear2_length = min($distance2 * $scale, 200);
                $bear2_x = 250 + $bear2_length * sin(deg2rad($bearing2));
                $bear2_y = 250 - $bear2_length * cos(deg2rad($bearing2));
                $svg .= '<line x1="250" y1="250" x2="' . $bear2_x . '" y2="' . $bear2_y . '" stroke="#f39c12" stroke-width="4"/>';
                $svg .= '<circle cx="' . $bear2_x . '" cy="' . $bear2_y . '" r="6" fill="#f39c12" stroke="#fff" stroke-width="2"/>';
                $svg .= '<text x="' . ($bear2_x + 10) . '" y="' . ($bear2_y - 10) . '" font-size="12" font-weight="bold" fill="#f39c12">P2</text>';
                
                // Target true course (red arrow)
                $target_x = 250 + 120 * sin(deg2rad($target_course));
                $target_y = 250 - 120 * cos(deg2rad($target_course));
                $svg .= '<line x1="250" y1="250" x2="' . $target_x . '" y2="' . $target_y . '" stroke="#e74c3c" stroke-width="5" marker-end="url(#arrowRed)"/>';
                
                // Arrow markers
                $svg .= '<defs>';
                $svg .= '<marker id="arrowBlue" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto" markerUnits="strokeWidth">';
                $svg .= '<path d="M0,0 L0,6 L9,3 z" fill="#3498db"/>';
                $svg .= '</marker>';
                $svg .= '<marker id="arrowRed" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto" markerUnits="strokeWidth">';
                $svg .= '<path d="M0,0 L0,6 L9,3 z" fill="#e74c3c"/>';
                $svg .= '</marker>';
                $svg .= '</defs>';
                
                $svg .= '</svg>';
                return $svg;
            }
            
            echo '<div class="results-with-diagram">';
            echo '<div class="results">';
            echo '<h2>Beregningsresultater:</h2>';
            echo '<div class="result-item">Målets sande kurs: <span class="result-value">' . number_format($target_course, 1) . '°</span></div>';
            echo '<div class="result-item">Målets relative kurs: <span class="result-value">' . number_format($relative_course, 1) . '°</span></div>';
            echo '<div class="result-item">Målets fart: <span class="result-value">' . number_format($target_speed, 1) . ' knob</span></div>';
            echo '<div class="result-item">TCPA: <span class="result-value">' . number_format($tcpa_minutes, 1) . ' minutter</span></div>';
            echo '<div class="result-item">CPA: <span class="result-value">' . number_format($cpa_distance, 2) . ' sømil</span></div>';
            
            if ($cpa_distance < 0.5) {
                echo '<div style="color: red; font-weight: bold; margin-top: 15px;">⚠️ ADVARSEL: Kollisionsrisiko!</div>';
            } elseif ($cpa_distance < 1.0) {
                echo '<div style="color: orange; font-weight: bold; margin-top: 15px;">⚠️ FORSIGTIG: Tæt passage!</div>';
            }
            echo '</div>';
            
            echo '<div class="compass-container">';
            echo '<div class="compass-title">360° Navigationsdiagram</div>';
            echo generateCompassDiagram($own_course, $bearing1, $bearing2, $distance1, $distance2, $target_course, $relative_course, $cpa_distance, $tcpa_hours, $x2, $y2, $rel_dx, $rel_dy);
            echo '<div class="legend">';
            echo '<div class="legend-item"><div class="legend-color" style="background-color: #3498db;"></div>Egen kurs (' . number_format($own_course, 1) . '°)</div>';
            echo '<div class="legend-item"><div class="legend-color" style="background-color: #27ae60;"></div>Pejling 1 - P1 (' . number_format($bearing1, 1) . '° - ' . number_format($distance1, 1) . 'nm)</div>';
            echo '<div class="legend-item"><div class="legend-color" style="background-color: #f39c12;"></div>Pejling 2 - P2 (' . number_format($bearing2, 1) . '° - ' . number_format($distance2, 1) . 'nm)</div>';
            echo '<div class="legend-item"><div class="legend-color" style="background-color: #e74c3c;"></div>Målets sande kurs (' . number_format($target_course, 1) . '°)</div>';
            echo '<div class="legend-item"><div class="legend-color" style="background-color: #8e44ad; background-image: repeating-linear-gradient(45deg, transparent, transparent 3px, white 3px, white 6px);"></div>Målets relative kurs (P1→P2 linje)</div>';
            echo '<div class="legend-item"><div class="legend-color" style="background-color: #e67e22; background-image: repeating-linear-gradient(45deg, transparent, transparent 3px, white 3px, white 6px);"></div>CPA - korteste afstand til målets bane</div>';
            echo '<div class="legend-item"><div class="legend-color" style="background-color: #ecf0f1; border: 1px dashed #bdc3c7;"></div>Afstandsringe (1nm intervaller)</div>';
            echo '<div class="legend-item"><div class="legend-color" style="background-color: #8e44ad; background-image: repeating-linear-gradient(45deg, transparent, transparent 3px, white 3px, white 6px);"></div>Målets bane (P1→P2→CPA)</div>';
            echo '</div>';
            echo '</div>';
            echo '</div>';
        }
        ?>
    </div>
</body>
</html>