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:
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.
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.
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 ); }