| New file |
| | |
| | | Lernziel: |
| | | |
| | | * HTTP-Server |
| | | * Syntax von URLs (=Bestandteil eines URL) |
| | | * Relative/absolute Pfade |
| | | |
| | | Task: |
| | | |
| | | * Identifizieren Sie alle URL in der Datei `index.html` |
| | | * Identifizieren Sie die Bestandteile von einer URL. |
| | | Welcher Bestandteil einer URL haben wir in eine ULR in `index.html` verwendet? |
| New file |
| | |
| | | html { |
| | | font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; |
| | | } |
| | | |
| | | h1 { |
| | | font-size: large; |
| | | } |
| | | |
| | | .container { |
| | | display: flex; |
| | | gap: 20px; |
| | | border: 0; |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | |
| | | .column { |
| | | flex: 1; |
| | | } |
| | | |
| | | @media (max-width: 600px) { |
| | | .container { |
| | | flex-direction: column; |
| | | } |
| | | } |
| | | |
| | | |
| New file |
| | |
| | | sync_git() { |
| | | SRC=$1 |
| | | DEST=$2 |
| | | echo $SRC |
| | | echo $DEST |
| | | mkdir -p $DEST |
| | | ls $DEST |
| | | rsync -aHAXxv --numeric-ids --delete --progress --exclude='.git' \ |
| | | --exclude='.gitignore' \ |
| | | --exclude='*/target' \ |
| | | --exclude='.idea' \ |
| | | --exclude='deploy.sh' \ |
| | | --exclude='.venv' \ |
| | | --exclude='site' \ |
| | | $SRC $DEST |
| | | |
| | | git -C $DEST add . |
| | | git -C $DEST commit -a -m "Commit Datum: $(date --iso-8601=seconds)" |
| | | git -C $DEST push origin main |
| | | |
| | | } |
| | | |
| | | sync_git ./ ../../codeberg.page/kurswinkel/ |
| New file |
| | |
| | | <!DOCTYPE html> |
| | | <html lang="en"> |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <title>Index</title> |
| | | <script src="https://cdn.jsdelivr.net/npm/jsxgraph/distrib/jsxgraphcore.js"></script> |
| | | <link rel="stylesheet" type="text/css" |
| | | href="https://cdn.jsdelivr.net/npm/jsxgraph/distrib/jsxgraph.css"> |
| | | <link rel="stylesheet" type="text/css" |
| | | href="./common.css"/> |
| | | </head> |
| | | <body> |
| | | <h1>Fluglinien mit Kurswinkel</h1> |
| | | <div class="container"> |
| | | <div class="column"> |
| | | <div id="box" class="jxgbox" style="width:800px; aspect-ratio: 1/1;"></div> |
| | | </div> |
| | | <div class="column"> |
| | | <div class="explain"> |
| | | <p>Drehe die Kugel so, dass der Startpunkt sich mit dem Punkt O deckt. |
| | | (el = 1.05, az = 2.09)</p> |
| | | <p>Der Winkel Nordpol-Startpunkt-Ziel ist der gesuchte Kurswinkel in der wahren Gestalt.</p> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <script type="module" src="tangente.js"></script> |
| | | </body> |
| | | </html> |
| New file |
| | |
| | | export const toRadians = (deg) => deg * Math.PI / 180; |
| | | export const toDegrees = (rad) => rad * 180 / Math.PI; |
| | | |
| | | export const azimuth = (longitude1, latitude1, longitude2, latitude2) =>{ |
| | | const [lon1, lat1, lon2, lat2] = [longitude1, latitude1, longitude2, latitude2].map(toRadians); |
| | | const _deltaLon = Math.abs(lon2 - lon1); |
| | | const PI = Math.PI; |
| | | const deltaLon = (_deltaLon) <= PI ? _deltaLon : 2*PI - _deltaLon; |
| | | const q = (Math.tan(PI/4 + lat2/2))/(Math.tan(PI/4 + lat1/2)); |
| | | const ln = 1/Math.log(q); |
| | | const alpha = Math.atan( deltaLon*ln ) * 180/PI; // degree! |
| | | const eastCourse = _deltaLon <= PI; |
| | | const direction = ( lon2>=lon1 && eastCourse) || (lon2<lon1 && !eastCourse); |
| | | if(lat2 > lat1 && direction) { |
| | | return alpha; |
| | | } else if(lat2 < lat1 && direction) { |
| | | return 180 - alpha; |
| | | } else if(lat2 < lat1 && !direction) { |
| | | return 180 + alpha; |
| | | } else if(lat2 > lat1 && !direction) { |
| | | return 360 - alpha; |
| | | } |
| | | if(lat2 === lat1) { |
| | | return direction ? 90 : 270; |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | import {azimuth} from "./sphere-calculator.js"; |
| | | |
| | | const toXYZ = (longitude, latitude) => { |
| | | const lon = (longitude * Math.PI) / 180; |
| | | const lat = (latitude * Math.PI) / 180; |
| | | |
| | | const x = RADIUS * Math.cos(lat) * Math.cos(lon); |
| | | const y = RADIUS * Math.cos(lat) * Math.sin(lon); |
| | | const z = RADIUS * Math.sin(lat); |
| | | |
| | | return [x, y, z]; |
| | | }; |
| | | |
| | | const toHomogeneousXYZ = (longitude, latitude) => { |
| | | const xyz = toXYZ(longitude, latitude); |
| | | xyz.unshift(0); |
| | | return xyz; |
| | | } |
| | | |
| | | const toLonLat = (x, y, z) => { |
| | | const R = Math.hypot(x, y, z); |
| | | const longitude = (Math.atan2(y, x) * 180) / Math.PI; // [-180, 180] |
| | | const latitude = (Math.asin(Math.max(-1, Math.min(1, z / R))) * 180) / Math.PI; // [-90, 90] |
| | | return [longitude, latitude]; |
| | | }; |
| | | |
| | | |
| | | const cross = (a, b) => [ |
| | | a[1] * b[2] - a[2] * b[1], |
| | | a[2] * b[0] - a[0] * b[2], |
| | | a[0] * b[1] - a[1] * b[0], |
| | | ]; |
| | | |
| | | const normalVector = ([lon1, lat1], [lon2, lat2]) => { |
| | | const n = cross(toXYZ(lon1, lat1), toXYZ(lon2, lat2)); |
| | | n.unshift(0); |
| | | return n; |
| | | } |
| | | |
| | | |
| | | const toGeographicLabel = (lon, lat) => { |
| | | return `${ lon.toFixed(1) }°|${ lat.toFixed(1)}°`; |
| | | } |
| | | |
| | | const solveProjectionPoint = (startX, startY, startZ, targetX, targetY, targetZ) => { |
| | | const t = targetX*targetX + targetY*targetY + targetZ*targetZ; |
| | | const k = -(startX*targetX + startY*targetY + startZ*targetZ - t) / t; |
| | | return [targetX + k * startX, targetY + k*startY, targetZ + k*startZ] |
| | | } |
| | | |
| | | // board commands |
| | | const RADIUS = 6; |
| | | const BOARD_SIZE = 14; |
| | | |
| | | const board = JXG.JSXGraph.initBoard( |
| | | 'box', { |
| | | boundingbox: [-BOARD_SIZE, BOARD_SIZE, BOARD_SIZE, -BOARD_SIZE], |
| | | //axis: true |
| | | }); |
| | | const bound = [-10, 10]; |
| | | |
| | | const startLongitude = board.create("slider", |
| | | [[-2, 10], [9, 10], [-180, -30, 180]], |
| | | {name: "Start LON.", precision: 2} |
| | | ); |
| | | const startLatitude = board.create("slider", |
| | | [[-2, 9], [9, 9], [-90, 60, 90]], |
| | | {name: "Start LAT.", precision: 2} |
| | | ); |
| | | |
| | | const targetLongitude = board.create("slider", |
| | | [[-2, -10], [9, -10], [-180, 120, 180]], |
| | | {name: "Ziel LON.", precision: 2} |
| | | ); |
| | | const targetLatitude = board.create("slider", |
| | | [[-2, -11], [9, -11], [-90, 0, 90]], |
| | | {name: "Ziel LAT.", precision: 2} |
| | | ); |
| | | |
| | | const displayAzimuth = () => { |
| | | const a = azimuth(startLongitude.Value(), startLatitude.Value(), |
| | | targetLongitude.Value(), targetLatitude.Value() |
| | | ); |
| | | return `Kurswinkel: ${a.toFixed(2)}°`; |
| | | } |
| | | const azimuthText = board.create('text', [8,6, displayAzimuth], {}); |
| | | |
| | | |
| | | const view = board.create('view3d', |
| | | [[-10, -10], [19, 19], |
| | | [bound, bound, bound]], |
| | | { |
| | | axesPosition: 'none', |
| | | xPlaneRear: {visible: false}, |
| | | yPlaneRear: {visible: false}, |
| | | zPlaneRear: {visible: false}, |
| | | // |
| | | az: { slider: { visible: true } }, |
| | | el: { slider: { visible: true } }, |
| | | bank: { slider: { visible: true } }, |
| | | } |
| | | ); |
| | | |
| | | const origin = view.create('point3d', [0,0,0], |
| | | {name:"O", fixed: true, highlight: false, showInfobox: false,} |
| | | ); |
| | | const earth = view.create('sphere3d', [origin, RADIUS]); |
| | | |
| | | const NORTH_POLE = [0, 90]; |
| | | const north_pole = toHomogeneousXYZ(...NORTH_POLE); |
| | | const equator = view.create('circle3d', [origin, north_pole, RADIUS], { |
| | | strokeColor:"red", fixed: true |
| | | }); |
| | | const northPoint = view.create('point3d', [toXYZ(...NORTH_POLE)], { |
| | | name:'N', fixed: true, highlight: true, showInfobox: false, |
| | | }); |
| | | |
| | | |
| | | const prime_meridian_normal = toHomogeneousXYZ(90, 0) |
| | | const prime_meridian = view.create('circle3d', [origin, prime_meridian_normal, RADIUS], { |
| | | strokeColor: "blue", |
| | | fixed: true |
| | | }); |
| | | |
| | | const startPoint = view.create('point3d', |
| | | () => [...toXYZ(startLongitude.Value(), startLatitude.Value())], |
| | | {id:'S', fixed: true, highlight: true, showInfobox: false,} |
| | | ); |
| | | startPoint.element2D.label.setText( () => "Start: " + |
| | | toGeographicLabel( ...toLonLat(startPoint.X(),startPoint.Y(), startPoint.Z() ) ) ); |
| | | const tangentPlan = view.create('circle3d', |
| | | [startPoint, () => [0, startPoint.X(), startPoint.Y(), startPoint.Z()], RADIUS], |
| | | {fillColor:"red", fillOpacity:0.25, fixed: true} |
| | | ); |
| | | |
| | | const targetPoint = view.create('point3d', |
| | | () => [...toXYZ(targetLongitude.Value(), targetLatitude.Value())], |
| | | {id: 'T', fixed: true, highlight: true, showInfobox: false,} |
| | | ); |
| | | targetPoint.element2D.label.setText( () => "Ziel: " + |
| | | toGeographicLabel( ...toLonLat(targetPoint.X(), targetPoint.Y(), targetPoint.Z() ) ) ); |
| | | const projectionPoint = view.create('point3d', |
| | | () => solveProjectionPoint( |
| | | startPoint.X(), startPoint.Y(), startPoint.Z(), |
| | | targetPoint.X(), targetPoint.Y(), targetPoint.Z() |
| | | ), |
| | | {id: 'P', name:"Prj. Ziel", fixed: true, highlight: true, showInfobox: false, strokeColor:"black", fillColor: "gray"} |
| | | ); |
| | | |
| | | const routeNormalVector = () => { |
| | | return normalVector( |
| | | [startLongitude.Value(), startLatitude.Value()], |
| | | [targetLongitude.Value(), targetLatitude.Value()] |
| | | ); |
| | | }; |
| | | const route = view.create('circle3d', [origin, routeNormalVector, RADIUS] ); |
| | | |
| | | |
| | | const meridianNormalVector = () => normalVector([startLongitude.Value(), startLatitude.Value()], NORTH_POLE); |
| | | const meridianPlan = view.create('circle3d', [origin, meridianNormalVector, RADIUS]); |
| | | const ot = view.create('line3d', [origin, startPoint]) |
| | | |
| | | const projectionDirectionVector = () => [startPoint.X(), startPoint.Y(), startPoint.Z()]; |
| | | const projectionLine = view.create('line3d', |
| | | [targetPoint, projectionDirectionVector, [0, Infinity]], |
| | | {strokeColor: "gray", dash: 2, strokeWidth: 1} |
| | | ); |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |