Jypeli  5
The simple game programming library
Shapes.cs
Siirry tämän tiedoston dokumentaatioon.
1 #region MIT License
2 /*
3  * Copyright (c) 2009 University of Jyväskylä, Department of Mathematical
4  * Information Technology.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #endregion
25 
26 /*
27  * Authors: Tero Jäntti, Tomi Karppinen, Janne Nikkanen.
28  */
29 
30 using System;
31 using System.ComponentModel;
32 using AdvanceMath;
33 using Physics2DDotNet;
34 using Physics2DDotNet.Shapes;
35 using Microsoft.Xna.Framework;
36 using Microsoft.Xna.Framework.Graphics;
37 
38 using XnaRectangle = Microsoft.Xna.Framework.Rectangle;
39 using XnaColor = Microsoft.Xna.Framework.Color;
40 using System.Reflection;
41 
42 
43 namespace Jypeli
44 {
48  public abstract class Shape
49  {
55  public abstract bool IsUnitSize { get; }
56 
57  internal abstract ShapeCache Cache { get; }
58 
62  public static readonly Ellipse Circle = new Ellipse();
63 
67  public static readonly Ellipse Ellipse = new Ellipse();
68 
72  public static readonly Rectangle Rectangle = new Rectangle();
73 
77  public static readonly Triangle Triangle = new Triangle();
78 
82  public static readonly Heart Heart = new Heart();
83 
87  public static readonly Star Star = new Star();
88 
92  public static readonly Shape Diamond = new RegularPolygon(4);
93 
97  public static readonly Shape Pentagon = new RegularPolygon( 5 );
98 
102  public static readonly Shape Hexagon = new RegularPolygon( 6 );
103 
107  public static readonly Shape Octagon = new RegularPolygon( 8 );
108 
118  public static Shape FromImage( Image image )
119  {
120  Texture2D texture = image.XNATexture;
121  IBitmap bm = new TextureBitmap( texture );
122  Vector2D[] vertices = VertexHelper.CreateFromBitmap( bm );
123 
124  for ( int i = 0; i < vertices.Length; i++ )
125  {
126  vertices[i].X /= texture.Width;
127  vertices[i].Y /= texture.Height;
128 
129  // The center of the texture coordinates is at top left corner, but the center of
130  // game objects is by default at the center of the object.
131  vertices[i] -= new Vector2D( (float)0.5, (float)0.5 );
132  }
133 
134  Vector[] polygonVertices = new Vector[vertices.Length];
135  for ( int i = 0; i < vertices.Length; i++ )
136  polygonVertices[i] = new Vector( vertices[i].X, vertices[i].Y );
137 
138  ShapeCache cache = new ShapeCache( polygonVertices );
139  return new Polygon( cache );
140  }
141 
146  public static Shape FromString( string shapeStr )
147  {
148  Type shapeClass = typeof( Shape );
149  BindingFlags flags = BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static;
150  FieldInfo selectedShape = shapeClass.GetField( shapeStr, flags );
151  return (Shape)selectedShape.GetValue( null );
152  }
153 
159  public static Shape CreateRegularPolygon( int vertexCount )
160  {
161  if ( vertexCount < 3 ) throw new ArgumentException( "You need at least 3 vertices to create a polygon!" );
162  return new RegularPolygon( vertexCount );
163  }
164 
165  internal static ShapeCache CreateRegularPolygonCache( int vertexCount )
166  {
167  double angleStep = 2 * Math.PI / vertexCount;
168  Int16 centerIndex = (Int16)vertexCount;
169 
170  Vector[] vertices = new Vector[vertexCount + 1];
171  IndexTriangle[] triangles = new IndexTriangle[vertexCount];
172  Int16[] outlineIndices = new Int16[vertexCount];
173 
174  for ( int i = 0; i < vertexCount; i++ )
175  {
176  double a = i * angleStep;
177  vertices[i] = new Vector( 0.5 * Math.Cos( a ), 0.5 * Math.Sin( a ) );
178  outlineIndices[i] = (Int16)i;
179  }
180  vertices[centerIndex] = Vector.Zero;
181 
182  for ( int i = 0; i < vertexCount - 1; i++ )
183  {
184  triangles[i] = new IndexTriangle( (Int16)i, centerIndex, (Int16)( i + 1 ) );
185  }
186  triangles[vertexCount - 1] = new IndexTriangle( (Int16)( vertexCount - 1 ), centerIndex, (Int16)0 );
187 
188  return new ShapeCache( vertices, triangles, outlineIndices );
189  }
190 
191  protected static bool SameSide( Vector a, Vector b, Vector p1, Vector p2 )
192  {
193  double cp1 = Vector.CrossProduct( b - a, p1 - a );
194  double cp2 = Vector.CrossProduct( b - a, p2 - a );
195  return cp1 * cp2 >= 0;
196  }
197 
198  protected static bool IsInsideTriangle( Vector p, Vector a, Vector b, Vector c )
199  {
200  Vector v0 = c - a;
201  Vector v1 = b - a;
202  Vector v2 = p - a;
203 
204  // Dot products between each side
205  double dot00 = Vector.DotProduct( v0, v0 );
206  double dot01 = Vector.DotProduct( v0, v1 );
207  double dot02 = Vector.DotProduct( v0, v2 );
208  double dot11 = Vector.DotProduct( v1, v1 );
209  double dot12 = Vector.DotProduct( v1, v2 );
210 
211  // Barycentric coordinates
212  double invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 );
213  double u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
214  double v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
215 
216  return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 );
217  }
218 
219  // TODO: Benchmark these two methods and use as default that which is faster
220 
221  protected bool IsInsideTriangles( Vector p )
222  {
223  for ( int i = 0; i < Cache.Triangles.Length; i++ )
224  {
225  Vector t1 = Cache.Vertices[Cache.Triangles[i].i1];
226  Vector t2 = Cache.Vertices[Cache.Triangles[i].i2];
227  Vector t3 = Cache.Vertices[Cache.Triangles[i].i3];
228 
229  if ( IsInsideTriangle( p, t1, t2, t3 ) )
230  return true;
231  }
232 
233  return false;
234  }
235 
236  protected bool IsInsideOutlines( Vector p )
237  {
238  Vector a, b;
239 
240  for ( int i = 0; i < Cache.OutlineVertices.Length - 1; i++ )
241  {
242  a = Cache.OutlineVertices[i];
243  b = Cache.OutlineVertices[i + 1];
244 
245  if ( !SameSide( a, b, p, Vector.Zero ) )
246  return false;
247  }
248 
249  a = Cache.OutlineVertices[Cache.OutlineVertices.Length - 1];
250  b = Cache.OutlineVertices[0];
251  if ( !SameSide( a, b, p, Vector.Zero ) )
252  return false;
253 
254  return true;
255  }
256 
257  protected bool IsInsideCircle( double x, double y, double r )
258  {
259  return x * x + y * y <= r;
260  }
261 
270  public virtual bool IsInside( double x, double y )
271  {
272  if ( Cache != null && Cache.Triangles != null )
273  {
274  // Use the shape cache triangles
275  return IsInsideTriangles( new Vector( x, y ) );
276  }
277  else if ( Cache != null && Cache.OutlineVertices != null )
278  {
279  // Use the shape cache outlines
280  return IsInsideOutlines( new Vector( x, y ) );
281  }
282  else
283  {
284  // Default: use the equation for a circle
285  return IsInsideCircle( x, y, 1 );
286  }
287  }
288  }
289 
293  public class Ellipse : Shape
294  {
295  private static ShapeCache _cache = CreateRegularPolygonCache( 64 );
296 
297  internal override ShapeCache Cache
298  {
299  get { return _cache; }
300  }
301 
302  public override bool IsUnitSize { get { return true; } }
303 
304  internal Ellipse() { }
305 
306  public override bool IsInside( double x, double y )
307  {
308  return IsInsideCircle( x, y, 1 );
309  }
310  }
311 
315  public class Rectangle : Shape
316  {
317  private static readonly Vector[] vertices = new Vector[]
318  {
319  new Vector( -0.5, -0.5 ),
320  new Vector( -0.5, 0.5 ),
321  new Vector( 0.5, -0.5 ),
322  new Vector( 0.5, 0.5 ),
323  };
324 
325  private static readonly IndexTriangle[] triangles = new IndexTriangle[]
326  {
327  new IndexTriangle( 0, 1, 2 ),
328  new IndexTriangle( 2, 1, 3 ),
329  };
330 
331  private static readonly Int16[] outlineIndices = new Int16[]
332  {
333  2, 3, 1, 0
334  };
335 
336  private static readonly ShapeCache _cache = new ShapeCache( vertices, triangles, outlineIndices );
337 
338  internal override ShapeCache Cache { get { return _cache; } }
339 
340  public override bool IsUnitSize { get { return true; } }
341 
342  internal Rectangle() { }
343 
344  public override bool IsInside( double x, double y )
345  {
346  return ( Math.Abs( x ) <= 1 && Math.Abs( y ) <= 1 );
347  }
348  }
349 
353  public class Heart : Shape
354  {
355  private static readonly Vector[] vertices = new Vector[]
356  {
357  new Vector( 0, -0.5 ),
358  new Vector( 0.5, 0.2 ),
359  new Vector( 0.4, 0.4 ),
360  new Vector( 0.25, 0.5 ),
361  new Vector( 0.1, 0.4 ),
362  new Vector( 0, 0.2 ),
363  new Vector( -0.1, 0.4 ),
364  new Vector( -0.25, 0.5 ),
365  new Vector( -0.4, 0.4 ),
366  new Vector( -0.5, 0.2 )
367  };
368 
369  private static readonly IndexTriangle[] triangles = new IndexTriangle[]
370  {
371  new IndexTriangle( 0, 9, 5 ),
372  new IndexTriangle( 8, 7, 6 ),
373  new IndexTriangle( 8, 6, 5 ),
374  new IndexTriangle( 9, 8, 5 ),
375  new IndexTriangle( 3, 2, 4 ),
376  new IndexTriangle( 4, 2, 5 ),
377  new IndexTriangle( 2, 1, 5 ),
378  new IndexTriangle( 5, 1, 0 ),
379  };
380 
381  private static readonly ShapeCache _cache = new ShapeCache( vertices, triangles );
382 
383  internal override ShapeCache Cache { get { return _cache; } }
384 
385  public override bool IsUnitSize { get { return true; } }
386 
387  internal Heart() { }
388  }
389 
393  public class Star : Shape
394  {
395  private static readonly Vector[] vertices = new Vector[]
396  {
397  new Vector( -0.5, -0.5 ),
398  new Vector( -0.25, 0 ),
399  new Vector( 0, -0.16 ),
400  new Vector( -0.5, 0.2 ),
401  new Vector( -0.15, 0.2 ),
402  new Vector( 0, 0.5 ),
403  new Vector( 0.15, 0.2 ),
404  new Vector( 0.5, 0.2 ),
405  new Vector( 0.25, 0 ),
406  new Vector( 0.5, -0.5 ),
407  };
408 
409  private static readonly IndexTriangle[] triangles = new IndexTriangle[]
410  {
411  new IndexTriangle( 0, 1, 2 ),
412  new IndexTriangle( 1, 3, 4 ),
413  new IndexTriangle( 1, 5, 8 ),
414  new IndexTriangle( 8, 6, 7 ),
415  new IndexTriangle( 9, 2, 8 ),
416  new IndexTriangle( 1, 8, 2 ),
417  };
418 
419  private static readonly Int16[] outlineIndices = new Int16[]
420  {
421  2, 9, 8, 7, 6, 5, 4, 3, 1, 0
422  };
423 
424  private static readonly ShapeCache _cache = new ShapeCache( vertices, triangles, outlineIndices );
425 
426  internal override ShapeCache Cache { get { return _cache; } }
427 
428  public override bool IsUnitSize { get { return true; } }
429 
430  internal Star() { }
431  }
432 
436  public class Triangle : Shape
437  {
438  private static readonly Vector[] vertices = new Vector[]
439  {
440  new Vector( 0, 0.5 ),
441  new Vector( 0.5, -0.5 ),
442  new Vector( -0.5, -0.5 ),
443  };
444 
445  private static readonly IndexTriangle[] triangles = new IndexTriangle[]
446  {
447  new IndexTriangle( 0, 1, 2 ),
448  };
449 
450  private static readonly Int16[] outlineIndices = new Int16[]
451  {
452  2, 1, 0
453  };
454 
455  private static readonly ShapeCache _cache = new ShapeCache( vertices, triangles, outlineIndices );
456 
457  internal override ShapeCache Cache { get { return _cache; } }
458 
459  public override bool IsUnitSize { get { return true; } }
460 
461  internal Triangle() { }
462 
463  public override bool IsInside( double x, double y )
464  {
465  return IsInsideTriangle( new Vector( x, y ), vertices[0], vertices[1], vertices[2] );
466  }
467  }
468 
472  public class RaySegment : Shape
473  {
474  internal override ShapeCache Cache
475  {
476  get { throw new Exception( "Cache is not defined for RaySegment" ); }
477  }
478 
479  public override bool IsUnitSize { get { return false; } }
480 
481  public Vector Origin;
483  public double Length;
484 
485  public RaySegment( Vector origin, Vector direction, double length )
486  {
487  this.Origin = origin;
488  this.Direction = direction;
489  this.Length = length;
490  }
491  }
492 
496  public class Polygon : Shape
497  {
498  private bool isUnitSize = true;
499  private ShapeCache _cache;
500 
506  public override bool IsUnitSize
507  {
508  get { return isUnitSize; }
509  }
510 
511  internal override ShapeCache Cache
512  {
513  get { return _cache; }
514  }
515 
516  public Polygon( ShapeCache cache )
517  : this( cache, true )
518  {
519  }
520 
521  public Polygon( ShapeCache cache, bool isUnitSize )
522  {
523  this._cache = cache;
524  this.isUnitSize = isUnitSize;
525  }
526  }
527 
531  internal class RegularPolygon : Polygon
532  {
533  public int CornerCount { get; internal set; }
534  public override bool IsUnitSize { get { return true; } }
535 
536  public RegularPolygon( int vertexCount )
537  : base( CreateRegularPolygonCache( vertexCount ) )
538  {
539  CornerCount = vertexCount;
540  }
541  }
542 
546  [EditorBrowsable( EditorBrowsableState.Never )]
547  public struct IndexTriangle
548  {
552  public Int16 i1, i2, i3;
553 
557  public IndexTriangle( Int16 i1, Int16 i2, Int16 i3 )
558  {
559  this.i1 = i1;
560  this.i2 = i2;
561  this.i3 = i3;
562  }
563 
567  public IndexTriangle( int i1, int i2, int i3 )
568  : this( (Int16)i1, (Int16)i2, (Int16)i3 )
569  {
570  }
571  }
572 
576  [EditorBrowsable( EditorBrowsableState.Never )]
577  public class ShapeCache
578  {
579  // The vertices are in counter-clockwise order
580  // because that is what the polygon shape of the physics
581  // engine expects.
582 
586  public readonly Vector[] OutlineVertices;
587 
591  public readonly Vector[] Vertices;
592 
596  public readonly IndexTriangle[] Triangles;
597 
604  public ShapeCache( Vector[] outlineVertices, IndexTriangle[] triangles )
605  {
606  this.Vertices = this.OutlineVertices = outlineVertices;
607  Triangles = triangles;
608  }
609 
615  public ShapeCache( Vector[] outlineVertices )
616  {
617  this.Vertices = this.OutlineVertices = outlineVertices;
618  this.Triangles = null;
619  }
620 
627  public ShapeCache( Vector[] vertices, IndexTriangle[] triangles, Int16[] outlineIndices )
628  {
629  Vertices = vertices;
630  Triangles = triangles;
631 
632  OutlineVertices = new Vector[outlineIndices.Length];
633  for ( int i = 0; i < outlineIndices.Length; i++ )
634  {
635  OutlineVertices[i] = vertices[outlineIndices[i]];
636  }
637  }
638  }
639 
644  internal class TextureBitmap : IBitmap
645  {
649  protected bool[,] bitmap;
650 
656  public TextureBitmap( Texture2D texture, Predicate<XnaColor> isOpaque )
657  {
658  XnaColor[] scanline = new XnaColor[texture.Width];
659  XnaRectangle srcRect = new XnaRectangle( 0, 0, texture.Width, 1 );
660 
661  bitmap = new bool[texture.Width, texture.Height];
662 
663  for ( int i = 0; i < texture.Height; i++ )
664  {
665  // Scan a line from the texture
666  srcRect.Y = i;
667  texture.GetData<XnaColor>( 0, srcRect, scanline, 0, texture.Width );
668 
669  for ( int j = 0; j < texture.Width; j++ )
670  {
671  // Flip the y-coordinates because the y-coordinates of the texture
672  // increase downwards.
673  bitmap[j, texture.Height - i - 1] = isOpaque( scanline[j] );
674  }
675  }
676  }
677 
683  public TextureBitmap( Texture2D texture )
684  : this( texture, IsOpaqueColor )
685  {
686  }
687 
691  public int Width
692  {
693  get { return bitmap.GetLength( 0 ); }
694  }
695 
699  public int Height
700  {
701  get { return bitmap.GetLength( 1 ); }
702  }
703 
707  public bool this[int x, int y]
708  {
709  get
710  {
711  if ( x < 0 || y < 0 || x >= Width || y >= Height ) { return false; }
712  return bitmap[x, y];
713  }
714  }
715 
722  public static bool IsOpaqueColor( XnaColor c )
723  {
724  return ( c.A >= 127 );
725  }
726  }
727 }
ShapeCache(Vector[] outlineVertices)
Luo kuvion pelkillä reuna-vertekseillä. Kuviolle ei tule tietoa kolmioista, näin ollen sitä ei voi tä...
Definition: Shapes.cs:615
static Shape CreateRegularPolygon(int vertexCount)
Luo säännöllisen monikulmion (polygonin)
Definition: Shapes.cs:159
ShapeCache(Vector[] outlineVertices, IndexTriangle[] triangles)
Luo kuvion kolmioilla, joiden avulla kuvio voidaan täyttää värillä. Kaikkien verteksien tulee olla ku...
Definition: Shapes.cs:604
static readonly Shape Hexagon
Heksagoni eli kuusikulmio.
Definition: Shapes.cs:102
readonly Vector [] OutlineVertices
Ulkoreunan verteksit, lueteltuna vastapäivään.
Definition: Shapes.cs:586
Kuvio.
Definition: Shapes.cs:48
bool IsInsideCircle(double x, double y, double r)
Definition: Shapes.cs:257
Tasasivuinen kolmio.
Definition: Shapes.cs:436
readonly Vector [] Vertices
Kaikki verteksit, ml. kolmioiden kulmapisteet.
Definition: Shapes.cs:591
Vector Direction
Definition: Shapes.cs:482
override bool IsInside(double x, double y)
Onko piste muodon sisällä. Pisteen koordinaatiston origo on muodon keskellä. Muoto on kokoa 1x1 jos I...
Definition: Shapes.cs:463
double Length
Definition: Shapes.cs:483
static bool IsInsideTriangle(Vector p, Vector a, Vector b, Vector c)
Definition: Shapes.cs:198
static readonly Shape Diamond
Timantti- / salmiakkikuvio
Definition: Shapes.cs:92
static readonly Heart Heart
Sydän.
Definition: Shapes.cs:82
static readonly Ellipse Ellipse
Ellipsi tai ympyrä.
Definition: Shapes.cs:67
Suorakulmio.
Definition: Shapes.cs:315
Int16 i1
Kulmapisteet.
Definition: Shapes.cs:552
static readonly Rectangle Rectangle
Suorakulmio.
Definition: Shapes.cs:72
Polygon(ShapeCache cache)
Definition: Shapes.cs:516
bool IsInsideTriangles(Vector p)
Definition: Shapes.cs:221
IndexTriangle(Int16 i1, Int16 i2, Int16 i3)
Luo uuden kolmion. Parametreina kulmapisteiden indeksit lueteltuna myötäpäivään.
Definition: Shapes.cs:557
readonly IndexTriangle [] Triangles
Kolmiot, joiden avulla kuvio voidaan täyttää värillä.
Definition: Shapes.cs:596
static readonly Star Star
Tähti.
Definition: Shapes.cs:87
static readonly Vector Zero
Nollavektori.
Definition: Vector.cs:61
virtual bool IsInside(double x, double y)
Onko piste muodon sisällä. Pisteen koordinaatiston origo on muodon keskellä. Muoto on kokoa 1x1 jos I...
Definition: Shapes.cs:270
Kuva.
Definition: Image.cs:24
override bool IsInside(double x, double y)
Onko piste muodon sisällä. Pisteen koordinaatiston origo on muodon keskellä. Muoto on kokoa 1x1 jos I...
Definition: Shapes.cs:344
static readonly Triangle Triangle
Tasasivuinen kolmio.
Definition: Shapes.cs:77
Polygon(ShapeCache cache, bool isUnitSize)
Definition: Shapes.cs:521
Sydän.
Definition: Shapes.cs:353
static bool SameSide(Vector a, Vector b, Vector p1, Vector p2)
Definition: Shapes.cs:191
Sisältää valmiiksi lasketut kolmiot, joiden avulla piirtäminen on suoraviivaista. ...
Definition: Shapes.cs:577
static double CrossProduct(Vector left, Vector right)
Ristitulo. Palauttaa kohtisuoraan vektoreita vastaan olevan uuden vektorin pituuden. Tuloksen merkki kertoo kumpaan suuntaan vektori osoittaa.
Definition: Vector.cs:153
static readonly Ellipse Circle
Ympyrä tai ellipsi.
Definition: Shapes.cs:62
static double DotProduct(Vector left, Vector right)
Pistetulo.
Definition: Vector.cs:140
IndexTriangle(int i1, int i2, int i3)
Luo uuden kolmion. Parametreina kulmapisteiden indeksit lueteltuna myötäpäivään.
Definition: Shapes.cs:567
Tähti.
Definition: Shapes.cs:393
bool IsInsideOutlines(Vector p)
Definition: Shapes.cs:236
Ympyrä.
Definition: Shapes.cs:293
static readonly Shape Pentagon
Pentagoni eli viisikulmio.
Definition: Shapes.cs:97
ShapeCache(Vector[] vertices, IndexTriangle[] triangles, Int16[] outlineIndices)
Luo kuvion, joka voidaan piirtää täytettynä värillä.
Definition: Shapes.cs:627
Vector Origin
Definition: Shapes.cs:481
Microsoft.Xna.Framework.Rectangle XnaRectangle
Definition: Shapes.cs:38
Monikulmio.
Definition: Shapes.cs:496
static Shape FromString(string shapeStr)
Luo muodon merkkijonosta, esim. "Circle"
Definition: Shapes.cs:146
RaySegment(Vector origin, Vector direction, double length)
Definition: Shapes.cs:485
2D-vektori.
Definition: Vector.cs:56
static Shape FromImage(Image image)
Luo kuvion annetusta kuvasta. Kuvassa tulee olla vain yksi yhtenäinen muoto (toisin sanoen kuvio ei v...
Definition: Shapes.cs:118
override bool IsInside(double x, double y)
Onko piste muodon sisällä. Pisteen koordinaatiston origo on muodon keskellä. Muoto on kokoa 1x1 jos I...
Definition: Shapes.cs:306
Muotojen määrityksessä käytettävä kolmio.
Definition: Shapes.cs:547
static readonly Shape Octagon
Oktagoni eli kahdeksankulmio.
Definition: Shapes.cs:107
abstract bool IsUnitSize
If true, the shape must be scaled by the size of the object that has the shape. Typically, an unit-sized object has width and height of 1.0.
Definition: Shapes.cs:55