Gozintograph: Unterschied zwischen den Versionen
Markierung: Zurückgesetzt |
|||
| Zeile 23: | Zeile 23: | ||
Im folgenden Beispiel werden fünf Bauteile \( B_1, B_2, B_3, B_4, B_5 \) aus vier Einzelteilen \( E_1, E_2, E_3, E_4 \) gefertigt. | Im folgenden Beispiel werden fünf Bauteile \( B_1, B_2, B_3, B_4, B_5 \) aus vier Einzelteilen \( E_1, E_2, E_3, E_4 \) gefertigt. | ||
Die Pfeile zeigen, welche Einzelteile in welches Bauteil eingehen. Die Zahlen an den Pfeilen geben die Stückzahl an. | Die Pfeile zeigen, welche Einzelteile in welches Bauteil eingehen. Die Zahlen an den Pfeilen geben die Stückzahl an. | ||
<!-- Variante | <!-- Variante A: JSXGraph --> | ||
<html> | <html> | ||
<style | <div id="gozinto_jsx" style="width:95vw; max-width:1000px; height:70vw; max-height:600px; margin-top:20px;"></div> | ||
</div> | |||
<script src="https://jsxgraph.org/distrib/jsxgraphcore.js"></script> | |||
<script> | <script> | ||
document.addEventListener("DOMContentLoaded", function () { | |||
var brd = JXG.JSXGraph.initBoard('gozinto_jsx', { | |||
boundingbox: [-1, 10, 15, -1], | |||
axis: false, | |||
showNavigation: false | |||
}); | }); | ||
// ----- Erzeuge Rechteck als Polygon mit fixierter Größe, aber draggable als Ganzes ----- | |||
function createRect(x,y,w,h,labelText) { | |||
var p1 = brd.create('point', [x, y], {visible:false, fixed:true}); | |||
var p2 = brd.create('point', [x+w, y], {visible:false, fixed:true}); | |||
var p3 = brd.create('point', [x+w, y-h], {visible:false, fixed:true}); | |||
var p4 = brd.create('point', [x, y-h], {visible:false, fixed:true}); | |||
var poly = brd.create('polygon', [p1,p2,p3,p4], { | |||
fillColor:'#3498db', fillOpacity:0.85, | |||
borders:{strokeWidth:2, strokeColor:'#1f4e78'}, | |||
vertices:{visible:false} | |||
}); | |||
// Damit das Rechteck als Ganzes verschiebbar ist: | |||
poly.draggable = true; | |||
// Zentrumspunkt als echter JSXGraph-Punkt (unsichtbar), damit wir ihn als Parent für Linien nutzen können | |||
var center = brd.create('point', [ | |||
function(){ return (p1.X()+p3.X())/2; }, | |||
function(){ return (p1.Y()+p3.Y())/2; } | |||
], {visible:false, fixed:true}); | |||
brd.create('text', [ | |||
function(){ return center.X(); }, | |||
function(){ return center.Y(); }, | |||
labelText | |||
], {anchorX:'middle', anchorY:'middle', strokeColor:'black', fontSize:14}); | |||
return {p1:p1,p2:p2,p3:p3,p4:p4, poly:poly, center:center, | |||
xMin: function(){ return Math.min(p1.X(), p2.X(), p3.X(), p4.X()); }, | |||
xMax: function(){ return Math.max(p1.X(), p2.X(), p3.X(), p4.X()); }, | |||
yMin: function(){ return Math.min(p1.Y(), p2.Y(), p3.Y(), p4.Y()); }, | |||
yMax: function(){ return Math.max(p1.Y(), p2.Y(), p3.Y(), p4.Y()); } | |||
}; | |||
} | |||
// ----- Kreis-Knoten (Punkt + Kreis + Label) ----- | |||
function createCircleNode(cx, cy, labelText) { | |||
var p = brd.create('point', [cx, cy], {visible:false}); | |||
var R = 0.35; | |||
brd.create('circle', [p, R], {strokeColor:'black', fillColor:'white', fillOpacity:1}); | |||
brd.create('text', [function(){return p.X();}, function(){return p.Y();}, labelText], | |||
{anchorX:'middle', anchorY:'middle', fontSize:12, strokeColor:'black'}); | |||
p.radius = R; | |||
return p; | |||
} | } | ||
// ----- Schnittpunkt eines Strahls (center -> target) mit dem Rechteckrand (analytisch) ----- | |||
// rect: Objekt mit xMin/xMax/yMin/yMax Funktionen | |||
// target: JSXGraph-Point (oder Objekt mit X()/Y()) | |||
function edgePointRect(rect, targetPoint) { | |||
// center coords (functions) | |||
var cx = function(){ return rect.center.X(); }; | |||
var cy = function(){ return rect.center.Y(); }; | |||
// create derived point: intersection computed analytically | |||
var pt = brd.create('point', [ | |||
function(){ | |||
var Cx = rect.center.X(); | |||
var Cy = rect.center.Y(); | |||
var Tx = targetPoint.X(); | |||
var Ty = targetPoint.Y(); | |||
var dx = Tx - Cx; | |||
var dy = Ty - Cy; | |||
// if direction is zero, return center | |||
if(Math.abs(dx) < 1e-9 && Math.abs(dy) < 1e-9) return Cx; | |||
var tCandidates = []; | |||
// check vertical sides x = xMin and xMax | |||
if(Math.abs(dx) > 1e-9) { | |||
var t1 = (rect.xMin() - Cx) / dx; | |||
var y1 = Cy + t1 * dy; | |||
if(t1>0 && y1 <= rect.yMax() + 1e-9 && y1 >= rect.yMin() - 1e-9) tCandidates.push(t1); | |||
var t2 = (rect.xMax() - Cx) / dx; | |||
var y2 = Cy + t2 * dy; | |||
if(t2>0 && y2 <= rect.yMax() + 1e-9 && y2 >= rect.yMin() - 1e-9) tCandidates.push(t2); | |||
} | |||
// check horizontal sides y = yMin and yMax | |||
if(Math.abs(dy) > 1e-9) { | |||
var t3 = (rect.yMin() - Cy) / dy; | |||
var x3 = Cx + t3 * dx; | |||
if(t3>0 && x3 <= rect.xMax() + 1e-9 && x3 >= rect.xMin() - 1e-9) tCandidates.push(t3); | |||
var t4 = (rect.yMax() - Cy) / dy; | |||
var x4 = Cx + t4 * dx; | |||
if(t4>0 && x4 <= rect.xMax() + 1e-9 && x4 >= rect.xMin() - 1e-9) tCandidates.push(t4); | |||
} | |||
if(tCandidates.length === 0) return Cx; // fallback | |||
// choose the smallest positive t (closest intersection along ray) | |||
var t = tCandidates.reduce(function(a,b){ return (a<b?a:b); }); | |||
return Cx + t * dx; | |||
}, | |||
function(){ | |||
var Cx = rect.center.X(); | |||
var Cy = rect.center.Y(); | |||
var Tx = targetPoint.X(); | |||
var Ty = targetPoint.Y(); | |||
var dx = Tx - Cx; | |||
var dy = Ty - Cy; | |||
if(Math.abs(dx) < 1e-9 && Math.abs(dy) < 1e-9) return Cy; | |||
var tCandidates = []; | |||
if(Math.abs(dx) > 1e-9) { | |||
var t1 = (rect.xMin() - Cx) / dx; | |||
var y1 = Cy + t1 * dy; | |||
if(t1>0 && y1 <= rect.yMax() + 1e-9 && y1 >= rect.yMin() - 1e-9) tCandidates.push(t1); | |||
var t2 = (rect.xMax() - Cx) / dx; | |||
var y2 = Cy + t2 * dy; | |||
if(t2>0 && y2 <= rect.yMax() + 1e-9 && y2 >= rect.yMin() - 1e-9) tCandidates.push(t2); | |||
} | |||
if(Math.abs(dy) > 1e-9) { | |||
var t3 = (rect.yMin() - Cy) / dy; | |||
var x3 = Cx + t3 * dx; | |||
if(t3>0 && x3 <= rect.xMax() + 1e-9 && x3 >= rect.xMin() - 1e-9) tCandidates.push(t3); | |||
var t4 = (rect.yMax() - Cy) / dy; | |||
var x4 = Cx + t4 * dx; | |||
if(t4>0 && x4 <= rect.xMax() + 1e-9 && x4 >= rect.xMin() - 1e-9) tCandidates.push(t4); | |||
} | |||
if(tCandidates.length === 0) return Cy; | |||
var t = tCandidates.reduce(function(a,b){ return (a<b?a:b); }); | |||
return Cy + t * dy; | |||
} | |||
], {visible:false}); | |||
return pt; | |||
} | |||
// ----- Punkt am Kreisrand in Richtung target ----- | |||
function edgePointCircle(circleCenter, R, targetPoint) { | |||
return brd.create('point', [ | |||
function(){ | |||
var cx = circleCenter.X(), cy = circleCenter.Y(); | |||
var tx = targetPoint.X(), ty = targetPoint.Y(); | |||
var dx = tx - cx, dy = ty - cy; | |||
var d = Math.sqrt(dx*dx + dy*dy); | |||
if(d < 1e-9) return cx; | |||
return cx + R * dx / d; | |||
}, | |||
function(){ | |||
var cx = circleCenter.X(), cy = circleCenter.Y(); | |||
var tx = targetPoint.X(), ty = targetPoint.Y(); | |||
var dx = tx - cx, dy = ty - cy; | |||
var d = Math.sqrt(dx*dx + dy*dy); | |||
if(d < 1e-9) return cy; | |||
return cy + R * dy / d; | |||
} | |||
], {visible:false}); | |||
} | |||
// | // ----- Verbindungsaufbau: exakte Endpunkte und Kreis in der Mitte ----- | ||
function | function makeConnection(rectFrom, rectTo, amount, yMid, xOffset) { | ||
// create circle center as reactive point (midpoint plus optional x offset) | |||
var circleCenter = brd.create('point', [ | |||
function(){ return (rectFrom.center.X() + rectTo.center.X())/2 + (xOffset||0); }, | |||
function(){ return yMid; } | |||
], {visible:false}); | |||
var circle = brd.create('circle', [circleCenter, 0.35], {strokeColor:'black', fillColor:'white'}); | |||
brd.create('text', [function(){return circleCenter.X();}, function(){return circleCenter.Y();}, amount], | |||
{anchorX:'middle', anchorY:'middle', fontSize:12}); | |||
// compute edge points | |||
var pFrom = edgePointRect(rectFrom, circleCenter); | |||
var pTo = edgePointRect(rectTo, circleCenter); | |||
var pCircleIn = edgePointCircle(circleCenter, 0.35, pFrom); | |||
var pCircleOut = edgePointCircle(circleCenter, 0.35, pTo); | |||
// line from rect -> circle (no arrowhead) | |||
brd.create('line', [pFrom, pCircleIn], {straightFirst:false, straightLast:false, strokeWidth:1.5}); | |||
// arrow from circle -> rect (arrow head at rect side) | |||
brd.create('arrow', [pCircleOut, pTo], {strokeWidth:1.8}); | |||
} | |||
// ---- Erzeuge Rechtecke ---- | |||
var E1 = createRect(0,8,2,1,'E1'); | |||
var E2 = createRect(3,8,2,1,'E2'); | |||
var E3 = createRect(6,8,2,1,'E3'); | |||
var E4 = createRect(9,8,2,1,'E4'); | |||
var B1 = createRect(0.5,3,2,1,'B1'); | |||
var B2 = createRect(3.5,3,2,1,'B2'); | |||
var B3 = createRect(6.5,3,2,1,'B3'); | |||
var B4 = createRect(9.5,3,2,1,'B4'); | |||
var B5 = createRect(12.5,3,2,1,'B5'); | |||
// ---- Verbindungen (mit kleinen offsets, damit Pfeilspitzen nicht überlappen) ---- | |||
makeConnection(E1, B1, "2", 6, -0.25); | |||
makeConnection(E2, B1, "1", 6, 0.25); | |||
makeConnection(E1, B2, "2", 6, -0.25); | |||
makeConnection(E2, B2, "1", 6, 0.25); | |||
makeConnection(E1, B3, "1", 6, -0.35); | |||
makeConnection(E2, B3, "1", 6, 0.0); | |||
makeConnection(E3, B3, "1", 6, 0.35); | |||
makeConnection(E1, B4, "2", 6, -0.35); | |||
makeConnection(E3, B4, "1", 6, 0.0); | |||
makeConnection(E4, B4, "1", 6, 0.35); | |||
makeConnection(E1, B5, "1", 6, -0.25); | |||
makeConnection(E4, B5, "2", 6, 0.25); | |||
} | }); | ||
</script> | </script> | ||
</html> | </html> | ||