WaBis

walter.bislins.ch

JSG: Zeichnen von Flächen mit Löchern

Um Flächen mit Löchern zu zeichnen, muss man mit Hilfe des Pfades mehrere Konturen zusammensetzen, damit diese dann als Einheit gefüllt werden können.

Damit ein Loch aus einer Fläche ausgespart wird, muss der Umlaufsinn der Lochkontur entgegen dem Umlaufsinn der Flächenkontur laufen.

Um zum Beispiel ein Rechteck mit einem runden Loch darin zu zeichnen, geht man folgendermassen vor:

  1. Pfad öffnen mit OpenPath()
  2. Rechteck normal zeichnen
  3. Kreis mit invertiertem Umlaufsinn zeichnen (negativer Radius)
  4. Pfad füllen mit Path()

Bei zusammengesetzten Konturen kann man den Umlaufsinn beeinflussen, indem die einzelnen Grafikelemente entsprechend aneinandergereiht werden. Polygone werden entweder in der enstprechenden Richtung berechnet oder mit den Funktionen JsgPolygon.Invert() bzw. JsgPolygon.InvertArrays() invertiert. Bei Kreisen kann der Umlaufsinn über das Vorzeichen des Radius invertiert werden. Bei Rechtecken kann der Umlaufsinn über das Argument Mode invertiert werden.

Koordinatensysteme und Umlaufsinn

In normalen nicht gespiegelten Windows-Koordinaten zeigt die Y-Achse nach oben auf dem Bildschirm. In solchen Window-Koordinaten ist der Umlaufsinn von Kreisen mit positivem Radius und von Rechtecken entgegen dem Uhrzeigersinn.

Bei Viewport- und Canvas-Koordinaten zeigt die Y-Achse immer nach unten. Daher sind in diesen Koordinatensystemen der Umlaufsinn von Kreisen mit positivem Radius und von Rechtecken gleich dem Uhrzeigersinn.

Marker sind ein Sonderfall: Ihr Umlaufsinn ist in jedem Koordinatensystem entgegen dem Uhrzeigersinn, wenn er nicht invertiert wurde. Dies muss beim Zeichnen in den verschiedenen Koordinatensystem berücksichtigt werden, wenn die Marker Löcher in eine Fläche stanzen sollen.

Die folgenden Grafiken verdeutlichen den Zusammanhang:

Window-Koordinatensystem

Viewport-Koordinatensystem

Die kleinen Kreise und Sterne sind Marker-Symbole, die mit der Funktion Marker() gezeichnet wurden. Ihr Umlaufsinn ist in beiden Koordinatensystem gleich. Die linken Symbole wurden mit normalem Marker-Umlaufsinn gezeichnet. Die rechten Symbole wurden mit invertiertem Umlaufsinn gezeichnet.

Marker sind wie Text nicht vom Koordinatensytem abhängig und ihre Orientierung richtet sich immer am Bildschirm aus, nicht am Koordinatensystem.

Das Rechteck und der grosse Kreis sind in beiden Grafiken identisch erzeugt worden. Da die beiden Koordinatensysteme zueinander an der X-Achse gespiegelt sind, ist der Umlaufsinn von Grosskreis und Rechteck in den beiden Bildern gegenläufig. Die Spiegelung ist auch der Grund, warum Kreis und Stern in den beiden Grafiken oben/unten vertauscht sind.

Ein Loch wird immer dann ausgestanzt, wenn der Umlaufsinn einer inneren Figur entgegen dem Umlaufsinn einer äusseren Figur ist.

Code der Grafik

var MarkerSize = 35;
var Marker1 = 'Circle';
var Marker2 = 'Star5';

function DrawFigure( jsg, win ) {
  // Area with Holes
  jsg.OpenPath();
  jsg.RectWH( 25, 25, 200, 150 );
  jsg.Circle( 250/2, 200/2, -50 ); // -50 => invert
  jsg.SetMarkerAttr( Marker1, MarkerSize );
  jsg.Marker( 50, 50, 0 );   // 0 => normal
  jsg.Marker( 200, 50, 4 );  // 4 => invert
  jsg.SetMarkerAttr( Marker2, MarkerSize );
  jsg.Marker( 50, 150, 0 );  // 0 => normal
  jsg.Marker( 200, 150, 4 ); // 4 => invert
  jsg.Path( 3 );

  // Coordinate Axes
  jsg.SetMarkerAttr( 'Arrow1', 8, 'blue', 'blue', 2 );
  jsg.Arrow( 5, 5, 50, 5 );
  jsg.Arrow( 5, 5, 5, 50 );

  // Rotation Arrow Circle
  jsg.SetMarkerAttr( 'Arrow1', 8, 'black', 'black', 2 );
  var poly = jsg.MakeEllipseArcPolygon( 125, 100, -50, 50, 0, 0, -45 );
  jsg.PolygonArrow( poly );

  // Rotation Arrow Circle Markers
  jsg.SetMarkerSize( 6 );
  var r = MarkerSize/2;
  var endAng = 60;
  if (!win) {
    r = -r;
    endAng = -60;
  }
  var poly = jsg.MakeEllipseArcPolygon( 50, 50, r, r, 0, 0, endAng );
  jsg.PolygonArrow( poly );
  var poly = jsg.MakeEllipseArcPolygon( 200, 50, -r, r, 0, 0, -endAng );
  jsg.PolygonArrow( poly );

  // Rotation Arrow Rectangle
  jsg.Arrow( 25, 25, 75, 25 );
  jsg.Arrow( 225, 75, 225, 125 );
  jsg.Arrow( 150, 175, 100, 175 );
  jsg.Arrow( 25, 125, 25, 75 );
}

var jsg1 = NewGraph2D( { Width: 250, Height: 200, DrawFunc: Draw1 } );

function Draw1(jsg) {
  jsg.SelectTrans('window');
  DrawBackground( jsg );
  DrawFigure( jsg, true );
}

var jsg2 = NewGraph2D( { Width: 250, Height: 200, DrawFunc: Draw2 } );

function Draw2(jsg) {
  jsg.SelectTrans('viewport');
  DrawBackground( jsg );
  DrawFigure( jsg, false );
}

function DrawBackground( jsg ) {
  jsg.SetAreaAttr( 'white', 'black', 1 );
  jsg.Frame( 3 );
  jsg.Grid( 25, 25 );
  jsg.SetAreaAttr( 'yellow', 'red', 2 );
}

Weitere Infos zur Seite
Erzeugt Mittwoch, 17. Februar 2016
von wabis
Zum Seitenanfang
Geändert Mittwoch, 8. Juni 2016
von wabis