208 lines
7.1 KiB
HTML
208 lines
7.1 KiB
HTML
<html>
|
|
<script src="https://www.50ohm.de/assets/jquery/3.7.1/jquery.min.js"></script>
|
|
<p>Hier kann man das Ganze interaktiv ausprobieren. Wenn der Abstrahlwinkel flach ist steigt die Reichweite. Ist der Abstrahlwinkel steil, so verkürzt sich die Reichweite.</p><br>
|
|
<table>
|
|
<tr>
|
|
<td>
|
|
Abstrahlwinkel $\alpha$:
|
|
</td>
|
|
<td>
|
|
<input type="range" class="slider" value="0" min="0" max="90" id="beamAngle">
|
|
</td>
|
|
<td>
|
|
<div id="beamAngleField" style="display:inline-block;">0</div> °.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<canvas id="myCanvas" style="border:0px; width:100%; display: block;">
|
|
Sorry, your browser does not support canvas.
|
|
</canvas>
|
|
|
|
<script>
|
|
|
|
// Setup Canvas:
|
|
const canvas = document.getElementById("myCanvas");
|
|
const ctx = canvas.getContext("2d");
|
|
|
|
// Functions:
|
|
function Vector(x, y) {
|
|
this.x = x || 0;
|
|
this.y = y || 0;
|
|
}
|
|
|
|
Vector.prototype = {
|
|
ort: function() {
|
|
return new Vector(this.y,-this.x);
|
|
},
|
|
add: function(v) {
|
|
return new Vector(this.x + v.x, this.y + v.y);
|
|
},
|
|
rotate : function(angle) {
|
|
return new Vector(
|
|
Math.cos(angle)*this.x - Math.sin(angle)*this.y,
|
|
Math.sin(angle)*this.x + Math.cos(angle)*this.y
|
|
);
|
|
},
|
|
sp: function(v) {
|
|
return this.x * v.x + this.y * v.y;
|
|
},
|
|
factor: function(f) {
|
|
return new Vector(f*this.x, f*this.y);
|
|
},
|
|
length : function () {
|
|
return Math.sqrt(this.x*this.x+this.y*this.y);
|
|
},
|
|
norm : function() {
|
|
return new Vector(this.x/this.length(),this.y/this.length());
|
|
},
|
|
negate : function() {
|
|
return new Vector(-1*this.x, -1*this.y);
|
|
},
|
|
angle: function(a) {
|
|
return Math.acos(this.sp(a) / (this.length() * a.length()));
|
|
},
|
|
clone: function() {
|
|
return new Vector(this.x, this.y);
|
|
},
|
|
};
|
|
|
|
function intersectionCircle(s, r, radius) {
|
|
// I'm already proud of the derivation :-P So my Abi wasn't in vain after all
|
|
sp = s.sp(r);
|
|
lambda1 = -1*(sp) + Math.sqrt(Math.pow(sp,2)-s.sp(s)+Math.pow(radius,2));
|
|
return s.add(r.factor(lambda1));
|
|
}
|
|
|
|
function intersectionCircle2(s, r, radius) {
|
|
// I'm already proud of the derivation :-P So my Abi wasn't in vain after all
|
|
sp = s.sp(r);
|
|
lambda2 = -1*(sp) - Math.sqrt(Math.pow(sp,2)-s.sp(s)+Math.pow(radius,2));
|
|
return s.add(r.factor(lambda2));
|
|
}
|
|
|
|
function drawLine(ctx, start, end, strokecolor, lineWidth) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(start.x, start.y);
|
|
ctx.lineTo(end.x, end.y);
|
|
ctx.lineWidth = lineWidth;
|
|
if(strokecolor != "") {
|
|
ctx.strokeStyle = strokecolor;
|
|
}
|
|
ctx.stroke();
|
|
}
|
|
|
|
function drawCircle(ctx, origin, radius, fillcolor, strokecolor, lineWidth){
|
|
ctx.beginPath();
|
|
ctx.arc(origin.x, origin.y, radius, 0, 2 * Math.PI, false);
|
|
if(fillcolor != "") {
|
|
ctx.fillStyle = fillcolor;
|
|
ctx.fill();
|
|
}
|
|
ctx.lineWidth = lineWidth;
|
|
if(strokecolor != "") {
|
|
ctx.strokeStyle = strokecolor;
|
|
}
|
|
ctx.stroke();
|
|
}
|
|
|
|
function drawArc(ctx, origin, radius, angle, fillcolor, strokecolor, lineWidth){
|
|
ctx.beginPath();
|
|
ctx.arc(origin.x, origin.y, radius, Math.PI/4, Math.PI/4+angle*Math.PI/180, false);
|
|
if(fillcolor != "") {
|
|
ctx.fillStyle = fillcolor;
|
|
ctx.fill();
|
|
}
|
|
ctx.lineWidth = lineWidth;
|
|
if(strokecolor != "") {
|
|
ctx.strokeStyle = strokecolor;
|
|
}
|
|
ctx.stroke();
|
|
}
|
|
|
|
|
|
function drawScene(ctx, angle) {
|
|
|
|
// Clean Canvas:
|
|
ctx.canvas.width = 600;
|
|
ctx.canvas.height = 200;
|
|
|
|
// Set origin to center:
|
|
ctx.translate(canvas.width * 0.5, canvas.height * 1);
|
|
|
|
// Flip Canvas to normal:
|
|
ctx.scale(1, -1);
|
|
|
|
// Origin:
|
|
M = new Vector(0,0);
|
|
|
|
// Set Radius
|
|
var radiusEarth = 100;
|
|
var radiusAtmosphere = 180;
|
|
|
|
// Sender Point:
|
|
S = new Vector(-radiusEarth/Math.sqrt(2),radiusEarth/Math.sqrt(2));
|
|
|
|
// Draw Antenna:
|
|
antennaTop = S.factor(1.2);
|
|
antennaMiddle = S.factor(1.1);
|
|
antennaRadius = antennaTop.length();
|
|
drawLine(ctx,S, antennaTop, "#000000", 1);
|
|
ast1 = S.rotate(0.75*Math.PI).norm();
|
|
ast2 = S.rotate(0.25*Math.PI).norm();
|
|
end1 = intersectionCircle2(antennaMiddle, ast1, antennaRadius);
|
|
end2 = intersectionCircle(antennaMiddle, ast2, antennaRadius);
|
|
drawLine(ctx, antennaMiddle, end1, "#000000", 1);
|
|
drawLine(ctx, antennaMiddle, end2, "#000000", 1);
|
|
|
|
// Create Vector nomalized orthogonal to the Senderpoint:
|
|
Sorth = S.ort().norm();
|
|
|
|
// Draw Earth and Atmosphere:
|
|
drawCircle(ctx, M, radiusEarth, "#49ace9", "", 1);
|
|
drawCircle(ctx, M, radiusAtmosphere, "", "#ffbab5", 25);
|
|
|
|
// Rotate this normalized vector with the beaming angle:
|
|
beam1 = Sorth.rotate(angle*Math.PI/180);
|
|
|
|
// Create the point where the beam intersects with the Atmosphere
|
|
cp1 = intersectionCircle(S, beam1, radiusAtmosphere);
|
|
|
|
// Draw beam 1:
|
|
drawLine(ctx, S, cp1, "#fe756c", 3);
|
|
|
|
// Calculate the angle between cp1neg and beam 1 neg:
|
|
cbAngle = cp1.angle(beam1);
|
|
|
|
// Calculate cp1neg:
|
|
cp1neg = cp1.negate();
|
|
|
|
// Rotate cp1neg by the cbAngle and normalize it:
|
|
beam2 = cp1neg.rotate(cbAngle).norm();
|
|
|
|
// Create the point where the beam intersects with the Earth Circle
|
|
cp2 = intersectionCircle2(cp1, beam2, radiusEarth);
|
|
|
|
// Draw beam 2:
|
|
drawLine(ctx, cp1, cp2, "#fe756c", 3);
|
|
|
|
// Create the point where ground reference intersects with Atmosphere
|
|
gp1 = intersectionCircle(S, Sorth, radiusAtmosphere);
|
|
drawLine(ctx, S, gp1, "#999999", 1);
|
|
gp2 = intersectionCircle2(S, Sorth, radiusAtmosphere);
|
|
drawLine(ctx, S, gp2, "#999999", 1);
|
|
|
|
// Draw Angle
|
|
drawArc(ctx, S, 40, angle, "", "#999999", 1);
|
|
}
|
|
|
|
drawScene(ctx, 0);
|
|
|
|
$("#beamAngle").on("change", function() {
|
|
console.log("DRAW");
|
|
angle = $(this).val();
|
|
drawScene(ctx, angle);
|
|
$('#beamAngleField').html(angle);
|
|
});
|
|
|
|
</script>
|
|
</html> |