Gozintograph: Unterschied zwischen den Versionen

 
(22 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 30: Zeile 30:
     height:50vw;
     height:50vw;
     max-width:1100px;
     max-width:1100px;
     max-height:480px;
     max-height:400px;
     border:0;
     border:0;
     margin:0;
     margin:0;
Zeile 75: Zeile 75:


<div class="gozinto-wrap">
<div class="gozinto-wrap">
<svg id="gozinto_svg" viewBox="0 0 1180 420" preserveAspectRatio="xMinYMin meet">
<svg id="gozinto_svg_2" viewBox="0 0 1200 450" preserveAspectRatio="xMinYMin meet">
</svg>
</svg>
</div>
</div>
Zeile 81: Zeile 81:
<script>
<script>
(function(){
(function(){
   const svg = document.getElementById("gozinto_svg");
   const svg = document.getElementById("gozinto_svg_2");


   // leicht reduzierte Abstände
   // leicht reduzierte Abstände
Zeile 317: Zeile 317:
</math>  
</math>  


gegeben. Beispielsweise lässt sich aus der ersten Spalte ablesen, dass 2 Einzelteile von E1, 1 Einzelteil von E2 sowie 0 Einzelteile von E3 und E4 für die Herstellung eines Bauteils B1 benötigt werden.
gegeben. Beispielsweise lässt sich aus der ersten Spalte ablesen, dass 2 Einzelteile von E1, 1 Einzelteil von E2 sowie 0 Einzelteile von E3 und E4 für die Herstellung eines Bauteils B1 benötigt werden.


=== Produktion von Spielwaren aus Rohstoffen über Zwischenprodukte ===
=== Produktion von Spielwaren aus Rohstoffen über Zwischenprodukte ===
Zeile 323: Zeile 323:
Ein Spielwarenhersteller produziert aus drei Rohstoffen \(R_1, R_2, R_3\) zunächst die beiden Zwischenprodukte \(Z_1, Z_2\), aus denen anschließend die drei Endprodukte \(E_1, E_2, E_3\) gefertigt werden.  
Ein Spielwarenhersteller produziert aus drei Rohstoffen \(R_1, R_2, R_3\) zunächst die beiden Zwischenprodukte \(Z_1, Z_2\), aus denen anschließend die drei Endprodukte \(E_1, E_2, E_3\) gefertigt werden.  


Die Pfeile im (hier nicht dargestellten) Gozintographen geben an, wie viele Tonnen eines Materials zur Produktion von 1 Tonne des entstehenden Produkts benötigt werden.   
Die Pfeile im Gozintographen geben an, wie viele Tonnen eines Materials zur Produktion von 1 Tonne des entstehenden Produkts benötigt werden.   
Beispiel: Für die Herstellung von 1 Tonne \(Z_1\) werden 3 Tonnen \(R_1\) und 4 Tonnen \(R_2\) benötigt.
Beispiel: Für die Herstellung von 1 Tonne \(Z_1\) werden 3 Tonnen \(R_1\) und 4 Tonnen \(R_2\) benötigt.
<!-- GOZINTOGRAPH: Rohstoffe → Zwischenprodukte → Endprodukte -->
<html>
<style>
  .gozinto-wrap {
    width:95vw;
    height:60vw;
    max-width:1200px;
    max-height:650px;
    border:0;
    margin:0;
    padding:0;
  }
  svg {
    width:100%;
    height:100%;
    touch-action:none;
    user-select:none;
    background:white;
  }
  .node-rect {
    fill:#3498db;
    stroke:#1f4e78;
    stroke-width:2;
    cursor:grab;
  }
  .node-text, .count-text {
    font-family:sans-serif;
    font-size:14px;
    fill:#000;
    pointer-events:none;
  }
  .edge-line {
    stroke:#000;
    stroke-width:2;
    fill:none;
  }
  .edge-arrow { fill:#000; }
  .count-circle {
    fill:#fff;
    stroke:#000;
    stroke-width:1.5;
  }
</style>
<div class="gozinto-wrap">
<svg id="gozinto_svg" viewBox="0 0 1180 600" preserveAspectRatio="xMinYMin meet">
</svg>
</div>
<script>
(function(){
  const svg = document.getElementById("gozinto_svg");
  const scale = 100;
  const yOffset = 0;
  const xOffsetGlobal = 120;
  function svgEl(name, attrs){
    const el = document.createElementNS("http://www.w3.org/2000/svg", name);
    for(const k in (attrs||{})) el.setAttribute(k, attrs[k]);
    return el;
  }
  function getSVGcoords(evt){
    const pt = svg.createSVGPoint();
    pt.x = evt.clientX;
    pt.y = evt.clientY;
    return pt.matrixTransform(svg.getScreenCTM().inverse());
  }
  function createNode(id, cx, cy, w, h, label){
    cx += xOffsetGlobal/scale;
    const g = svgEl("g", {"data-id":id});
    const rect = svgEl("rect", {
      class:"node-rect",
      x:(cx-w/2)*scale, y:(cy-h/2)*scale + yOffset,
      width:w*scale, height:h*scale, rx:6, ry:6
    });
    const text = svgEl("text", {
      class:"node-text",
      x:cx*scale, y:cy*scale+yOffset,
      "text-anchor":"middle",
      "dominant-baseline":"middle"
    });
    text.textContent = label;
    g.appendChild(rect);
    g.appendChild(text);
    svg.appendChild(g);
    const node = {id,cx,cy,w,h,rect,text,g};
    let dragging=false, start={};
    rect.addEventListener("pointerdown", e=>{
      rect.setPointerCapture(e.pointerId);
      dragging=true;
      const p = getSVGcoords(e);
      start = {px:p.x, py:p.y, cx:node.cx, cy:node.cy};
    });
    rect.addEventListener("pointermove", e=>{
      if(!dragging) return;
      const p = getSVGcoords(e);
      node.cx = start.cx + (p.x - start.px)/scale;
      node.cy = start.cy + (p.y - start.py)/scale;
      updateNode(node);
      updateAllEdges();
    });
    rect.addEventListener("pointerup", e=>{
      dragging=false;
      rect.releasePointerCapture(e.pointerId);
    });
    return node;
  }
  function updateNode(n){
    n.rect.setAttribute("x",(n.cx-n.w/2)*scale);
    n.rect.setAttribute("y",(n.cy-n.h/2)*scale+yOffset);
    n.text.setAttribute("x",n.cx*scale);
    n.text.setAttribute("y",n.cy*scale+yOffset);
  }
  function intersectRectBorder(node, tx, ty){
    const cx=node.cx, cy=node.cy, w2=node.w/2, h2=node.h/2;
    const dx=tx-cx, dy=ty-cy;
    let pts=[];
    if(Math.abs(dx)>1e-9){
      let t1=(-w2)/dx; let y1=cy+t1*dy;
      if(t1>0 && y1>=cy-h2 && y1<=cy+h2) pts.push({x:cx-w2,y:y1,t:t1});
      let t2=(w2)/dx; let y2=cy+t2*dy;
      if(t2>0 && y2>=cy-h2 && y2<=cy+h2) pts.push({x:cx+w2,y:y2,t:t2});
    }
    if(Math.abs(dy)>1e-9){
      let t3=(-h2)/dy; let x3=cx+t3*dx;
      if(t3>0 && x3>=cx-w2 && x3<=cx+w2) pts.push({x:x3,y:cy-h2,t:t3});
      let t4=(h2)/dy; let x4=cx+t4*dx;
      if(t4>0 && x4>=cx-w2 && x4<=cx+w2) pts.push({x:x4,y:cy+h2,t:t4});
    }
    pts.sort((a,b)=>a.t-b.t);
    return pts[0] || {x:cx,y:cy};
  }
  function pointOnCircle(cx,cy,R,tx,ty){
    const dx=tx-cx, dy=ty-cy;
    const d=Math.sqrt(dx*dx+dy*dy);
    if(d<1e-9) return {x:cx,y:cy};
    return {x:cx+R*dx/d, y:cy+R*dy/d};
  }
  function makeArrowHead(x,y,ux,uy,size){
    let px=-uy, py=ux;
    return `M ${x} ${y}
            L ${x-ux*size+px*size*0.5} ${y-uy*size+py*size*0.5}
            L ${x-ux*size-px*size*0.5} ${y-uy*size-py*size*0.5} Z`;
  }
  const edges=[];
  function makeConnection(fromNode,toNode,amount,yMid,xOffset){
    const g=svgEl("g",{});
    const lineA=svgEl("path",{class:"edge-line"});
    const lineB=svgEl("path",{class:"edge-line"});
    const circle=svgEl("circle",{class:"count-circle"});
    const text=svgEl("text",{class:"count-text"});
    const arrow=svgEl("path",{class:"edge-arrow"});
    text.textContent=amount;
    g.appendChild(lineA);
    g.appendChild(lineB);
    g.appendChild(circle);
    g.appendChild(text);
    g.appendChild(arrow);
    svg.appendChild(g);
    let e={fromNode,toNode,amount,yMid,xOffset,circle,text,lineA,lineB,arrow};
    edges.push(e);
    updateEdge(e);
  }
  function updateEdge(e){
    const cx=(e.fromNode.cx+e.toNode.cx)/2+(e.xOffset||0);
    const cy=e.yMid;
    const R=0.14;
    const pF=intersectRectBorder(e.fromNode,cx,cy);
    const pT=intersectRectBorder(e.toNode,cx,cy);
    const pCircleIn=pointOnCircle(cx,cy,R,pF.x,pF.y);
    const pCircleOut=pointOnCircle(cx,cy,R,pT.x,pT.y);
    const px=p=>[p.x*scale, p.y*scale+yOffset];
    const F=px(pF), Ci=px(pCircleIn), Co=px(pCircleOut), T=px(pT);
    e.lineA.setAttribute("d",`M ${F[0]} ${F[1]} L ${Ci[0]} ${Ci[1]}`);
    e.lineB.setAttribute("d",`M ${Co[0]} ${Co[1]} L ${T[0]} ${T[1]}`);
    e.circle.setAttribute("cx",cx*scale);
    e.circle.setAttribute("cy",cy*scale+yOffset);
    e.circle.setAttribute("r",R*scale);
    e.text.setAttribute('x', cx*scale-5);
    e.text.setAttribute('y', cy*scale + yOffset+5);
    let ux=T[0]-Co[0], uy=T[1]-Co[1];
    let L=Math.sqrt(ux*ux+uy*uy); if(L<1e-6) L=1;
    ux/=L; uy/=L;
    e.arrow.setAttribute("d",makeArrowHead(T[0],T[1],ux,uy,10));
  }
  function updateAllEdges(){ edges.forEach(updateEdge); }
  // -----------------------------------------------------
  // NODES
  // -----------------------------------------------------
  const nodes={};
  // Rohstoffe (oben)
  nodes.R1=createNode("R1",0,0.8,1.0,0.5,"R1");
  nodes.R2=createNode("R2",2.5,0.8,1.0,0.5,"R2");
  nodes.R3=createNode("R3",5.0,0.8,1.0,0.5,"R3");
  // Zwischenprodukte (Mitte)
  nodes.Z1=createNode("Z1",1.2,3.3,1.0,0.5,"Z1");
  nodes.Z2=createNode("Z2",3.0,3.3,1.0,0.5,"Z2");
  // Endprodukte (unten)
  nodes.E1=createNode("E1",0.5,5.8,1.0,0.5,"E1");
  nodes.E2=createNode("E2",2.5,5.8,1.0,0.5,"E2");
  nodes.E3=createNode("E3",4.5,5.8,1.0,0.5,"E3");
  // -----------------------------------------------------
  // VERBINDUNGEN
  // gemäß Tabellen:
  // Rohstoffe → Zwischenprodukte
  // R1→Z1: 3  | R1→Z2: 1
  // R2→Z1: 4  | R2→Z2: 2
  // R3→Z1: 0  | R3→Z2: 3
  // Zwischenprodukte → Endprodukte
  // Z1: (E1=2, E2=1, E3=0)
  // Z2: (E1=1, E2=3, E3=2)
  // -----------------------------------------------------
  // R1
  makeConnection(nodes.R1,nodes.Z1,"3",1.8,-0.3);
  makeConnection(nodes.R1,nodes.Z2,"1",1.8, 0.4);
  // R2
  makeConnection(nodes.R2,nodes.Z1,"4",1.8,-0.2);
  makeConnection(nodes.R2,nodes.Z2,"2",1.8, 0.2);
  // R3
  makeConnection(nodes.R3,nodes.Z2,"3",1.8, 0.0);
  // Z1 → Endprodukte
  makeConnection(nodes.Z1,nodes.E1,"2",4.6,-0.2);
  makeConnection(nodes.Z1,nodes.E2,"1",4.6, 0.2);
  // Z2 → Endprodukte
  makeConnection(nodes.Z2,nodes.E1,"1",4.6,-0.3);
  makeConnection(nodes.Z2,nodes.E2,"3",4.6, 0.0);
  makeConnection(nodes.Z2,nodes.E3,"2",4.6, 0.3);
  updateAllEdges();
})();
</script>
</html>


Die vollständigen Mengen seien wie folgt definiert:
Die vollständigen Mengen seien wie folgt definiert:


{| class="wikitable"
{| class="wikitable"
|+ '''Materialbedarf der Rohstoffe für Zwischenprodukte'''
!              !! Z1 !! Z2
!              !! Z1 !! Z2
|-
|-
Zeile 340: Zeile 623:


{| class="wikitable"
{| class="wikitable"
|+ '''Materialbedarf der Zwischenprodukte für Endprodukte'''
!              !! E1 !! E2 !! E3
!              !! E1 !! E2 !! E3
|-
|-
Zeile 361: Zeile 643:
1 & 3 & 2
1 & 3 & 2
\end{pmatrix}
\end{pmatrix}
\]
</math>


:<math>
:<math>
Zeile 394: Zeile 676:
</math>
</math>


Damit lautet die **Gozintomatrix Rohstoffe → Endprodukte**:
:<math>
RE =
\begin{pmatrix}
7 & 6 & 2 \\
10 & 10 & 4 \\
3 & 9 & 6
\end{pmatrix}
</math>
=== Interpretation ===
Die Matrix zeigt, wie viele Tonnen der Rohstoffe \(R_1, R_2, R_3\) jeweils zur Herstellung von 1 Tonne der Endprodukte \(E_1, E_2, E_3\) notwendig sind.   
Die Matrix zeigt, wie viele Tonnen der Rohstoffe \(R_1, R_2, R_3\) jeweils zur Herstellung von 1 Tonne der Endprodukte \(E_1, E_2, E_3\) notwendig sind.   
Beispielsweise bedeutet die erste Spalte:
Beispielsweise bedeutet die erste Spalte:


*Für 1 Tonne \(E_1\) werden benötigt:
Für 1 Tonne \(E_1\) werden benötigt:
* 7 Tonnen \(R_1\)   
* 7 Tonnen \(R_1\)   
* 10 Tonnen \(R_2\)   
* 10 Tonnen \(R_2\)   
* 3 Tonnen \(R_3\)
* 3 Tonnen \(R_3\)


Dies ergibt sich daraus, dass die Zwischenprodukte Z1 und Z2 selbst wiederum aus Rohstoffen bestehen.
Dies ergibt sich daraus, dass die Zwischenprodukte Z1 und Z2 selbst wiederum aus Rohstoffen bestehen.