00001 namespace Grendel.Base { 00002 using System; 00003 using System.Text; 00004 using System.Globalization; 00005 using System.Diagnostics; 00006 using System.Drawing.Drawing2D; 00007 using System.Drawing; 00008 using System.Collections.Generic; 00009 00013 public struct Position { 00014 double x; 00015 double y; 00016 00020 public static readonly Position Origin = new Position(0.0, 0.0); 00021 00022 public Position(double x, double y) { 00023 this.x = x; 00024 this.y = y; 00025 } 00026 00027 public double X { 00028 get {return x;} 00029 set {x = value;} 00030 } 00031 00032 public double Y { 00033 get {return y;} 00034 set {y = value;} 00035 } 00036 00040 public double Distance(Position p) { 00041 return Math.Sqrt( (X-p.X)*(X-p.X) + (Y-p.Y)*(Y-p.Y) ); 00042 } 00043 00044 00048 public bool IsInside(Position leftTop, Position rightBottom) { 00049 return X >= leftTop.X && X <= rightBottom.X && Y >= leftTop.Y && Y <= rightBottom.Y; 00050 } 00051 00055 [Obsolete("Use vector operation instead")] 00056 public Position ShiftBy(double dx, double dy) { 00057 return new Position(X+dx, Y+dy); 00058 } 00059 00063 public bool Equals (Position p) { 00064 return Math.Abs(X - p.X) < 1e-6 && Math.Abs(Y - p.Y) < 1e-6; 00065 } 00066 00067 public override bool Equals (object o) 00068 { 00069 if (o is Position) 00070 return Equals((Position)o); 00071 else 00072 return false; 00073 } 00074 00075 public static bool operator== (Position p1, Position p2) { 00076 return p1.Equals(p2); 00077 } 00078 00079 public static bool operator!= (Position p1, Position p2) { 00080 return !p1.Equals(p2); 00081 } 00082 00083 public override int GetHashCode () 00084 { 00085 return X.GetHashCode() ^ Y.GetHashCode(); 00086 } 00087 00088 public override string ToString () 00089 { 00090 return string.Format("[{0}, {1}]", X, Y); 00091 } 00092 00096 public static Vector operator- (Position target, Position origin) { 00097 return new Vector(target.X - origin.X, target.Y - origin.Y); 00098 } 00099 00103 public static Position operator+ (Position origin, Vector shift) { 00104 return new Position(origin.X + shift.X, origin.Y + shift.Y); 00105 } 00106 00107 public bool IsLeftFrom(Position p) { 00108 return X < p.X; 00109 } 00110 00111 public bool IsRightFrom(Position p) { 00112 return X > p.X; 00113 } 00114 00115 public bool IsAbove(Position p) { 00116 return Y < p.Y; 00117 } 00118 00119 public bool IsBelow(Position p) { 00120 return Y > p.Y; 00121 } 00122 } 00123 00127 public struct Vector { 00128 private double x; 00129 private double y; 00130 00131 public Vector(double x, double y) { 00132 this.x = x; 00133 this.y = y; 00134 } 00135 00136 public double X { 00137 get {return x;} 00138 set {x = value;} 00139 } 00140 00141 public double Y { 00142 get {return y;} 00143 set {y = value;} 00144 } 00145 00146 00150 public static double operator* (Vector v1, Vector v2) { 00151 return v1.X *v2.X + v1.Y * v2.Y; 00152 } 00153 00157 public static Vector operator* (double scalar, Vector vector) { 00158 return new Vector(scalar * vector.X, scalar * vector.Y); 00159 } 00160 00164 public double Length { 00165 get { 00166 return Math.Sqrt(this*this); 00167 } 00168 } 00169 00173 public bool Equals (Vector p) 00174 { 00175 return Math.Abs(X - p.X) < 1e-6 00176 && Math.Abs(Y - p.Y) < 1e-6; 00177 } 00178 00179 public override bool Equals (object o) 00180 { 00181 if (o is Vector) 00182 return Equals((Position)o); 00183 else 00184 return false; 00185 } 00186 00187 public static bool operator== (Vector p1, Vector p2) { 00188 return p1.Equals(p2); 00189 } 00190 00191 public static bool operator!= (Vector p1, Vector p2) { 00192 return !p1.Equals(p2); 00193 } 00194 00195 public override int GetHashCode () 00196 { 00197 return X.GetHashCode() ^ Y.GetHashCode(); 00198 } 00199 00200 public override string ToString () 00201 { 00202 return string.Format("({0}, {1})", X, Y); 00203 } 00204 00205 } 00206 00210 public struct Color { 00211 private byte red; 00212 private byte green; 00213 private byte blue; 00214 private byte transparence; 00215 00216 public Color (byte redComponent, byte greenComponent, byte blueComponent) { 00217 red = redComponent; 00218 green = greenComponent; 00219 blue = blueComponent; 00220 transparence = 0; 00221 } 00222 00223 public Color (byte redComponent, byte greenComponent, byte blueComponent, 00224 byte transparence){ 00225 red = redComponent; 00226 green = greenComponent; 00227 blue = blueComponent; 00228 this.transparence = transparence; 00229 } 00230 00231 public Color (int redComponent, int greenComponent, int blueComponent) 00232 : this((byte)redComponent, (byte)greenComponent, (byte)blueComponent) {} 00233 00234 public Color (int redComponent, int greenComponent, int blueComponent, int transparence) 00235 : this((byte)redComponent, (byte)greenComponent, (byte)blueComponent, (byte)transparence) 00236 {} 00237 00241 public byte RedComponent { 00242 get {return red;} 00243 set {red = value;} 00244 } 00245 00249 public byte GreenComponent { 00250 get {return green;} 00251 set {green = value;} 00252 } 00256 public byte BlueComponent { 00257 get {return blue;} 00258 set {blue = value;} 00259 } 00260 00264 public byte Transparence { 00265 get { 00266 return transparence; 00267 } 00268 set { 00269 transparence = value; 00270 } 00271 } 00272 00276 public Color WithTransparence(byte transparence) { 00277 Color clone = this; 00278 clone.Transparence = transparence; 00279 return clone; 00280 } 00281 00288 public Color Mix(Color addMixedColor, double quantity) { 00289 byte nred = (byte)((red + quantity*addMixedColor.red) / (1+quantity)); 00290 byte ngreen = (byte)((green + quantity*addMixedColor.green) / (1+quantity)); 00291 byte nblue = (byte)((blue + quantity*addMixedColor.blue) / (1+quantity)); 00292 byte ntrans = (byte)((transparence + quantity*addMixedColor.transparence) / (1+quantity)); 00293 return new Color(nred, ngreen, nblue, ntrans); 00294 } 00299 public Color Mix(Color addMixedColor) { 00300 return Mix(addMixedColor, 1.0); 00301 } 00302 00308 public static ColorQuantity operator* (double quantity, Color addmixedColor) { 00309 return new ColorQuantity(quantity, addmixedColor); 00310 } 00311 00317 public static Color operator+ (Color color, Color addMixedColor) { 00318 return color.Mix(addMixedColor, 1.0); 00319 } 00320 00325 public static Color operator+ (Color color, ColorQuantity colorQuantity) { 00326 return color.Mix(colorQuantity.color, colorQuantity.quantity); 00327 } 00328 00332 public override string ToString () { 00333 return string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", 00334 RedComponent, GreenComponent, BlueComponent, Transparence); 00335 } 00336 00340 static public Color Parse(string text) { 00341 byte red = byte.Parse(text.Substring(1,2), NumberStyles.HexNumber); 00342 byte green = byte.Parse(text.Substring(3,2), NumberStyles.HexNumber); 00343 byte blue = byte.Parse(text.Substring(5,2), NumberStyles.HexNumber); 00344 byte trans = byte.Parse(text.Substring(7,2), NumberStyles.HexNumber); 00345 return new Color(red, green, blue, trans); 00346 } 00347 00348 public static readonly Color Red = new Color(255,0,0); 00349 public static readonly Color Green = new Color(0,255,0); 00350 public static readonly Color Blue = new Color(0,0,255); 00351 public static readonly Color White = new Color(255,255,255); 00352 public static readonly Color Black = new Color(0,0,0); 00353 public static readonly Color Magenta = new Color(255,0,255); 00354 public static readonly Color Cyan = new Color(0,255,255); 00355 public static readonly Color Yellow = new Color(255,255,0); 00356 public static readonly Color Gray = new Color(128,128,128); 00357 public static readonly Color DarkGray = new Color(64,64,64); 00358 public static readonly Color LightGray = new Color(192,192,192); 00359 00364 public static readonly Color Empty = new Color(255, 255, 255, 255); 00365 } 00366 00370 public struct ColorQuantity { 00371 internal double quantity; 00372 internal Color color; 00373 00374 internal ColorQuantity(double quantity, Color color) { 00375 this.quantity = quantity; 00376 this.color = color; 00377 } 00378 } 00379 00384 public struct MouseButtons { 00385 bool left; 00386 bool middle; 00387 bool right; 00388 00389 internal MouseButtons(bool left, bool middle, bool right) { 00390 this.left = left; 00391 this.right = right; 00392 this.middle = middle; 00393 } 00394 00398 public bool IsPressedLeft { 00399 get { return left;} 00400 } 00401 00405 public bool IsPressedMiddle { 00406 get { return middle;} 00407 } 00408 00412 public bool IsPressedRight { 00413 get { return right;} 00414 } 00415 00419 public bool IsPressedAny { 00420 get { return IsPressedLeft || IsPressedMiddle || IsPressedRight;} 00421 } 00422 } 00423 00427 public enum FontStyle { 00428 Normal, 00429 Italic, 00430 Bold, 00431 BoldItalic 00432 } 00433 00437 public enum GenericFontFamily { 00438 Unknown, 00439 Serif, 00440 SansSerif, 00441 Monospace 00442 } 00443 00447 public struct Font { 00448 private string fontfamily; 00449 private GenericFontFamily genericFamily; 00450 private double size; 00451 private FontStyle style; 00452 00456 public FontStyle Style { 00457 get { 00458 return style; 00459 } 00460 set { 00461 style = value; 00462 } 00463 } 00464 00468 public double Size { 00469 get { 00470 return size; 00471 } 00472 set { 00473 size = value; 00474 } 00475 } 00476 00482 public GenericFontFamily GenericFamily { 00483 get { 00484 return genericFamily; 00485 } 00486 set { 00487 genericFamily = value; 00488 } 00489 } 00490 00495 public string FontFamily { 00496 get { 00497 return fontfamily; 00498 } 00499 set { 00500 fontfamily = value; 00501 } 00502 } 00503 00508 public bool IsGeneric { 00509 get {return GenericFamily != GenericFontFamily.Unknown;} 00510 } 00511 00516 public Font(GenericFontFamily genericFontFamily) 00517 : this(genericFontFamily, 12, FontStyle.Normal) {} 00518 00523 public Font(string fontFamily) 00524 : this(fontFamily, 12.0, FontStyle.Normal) {} 00525 00529 public Font(GenericFontFamily genericFontFamily, double size, FontStyle style) { 00530 Debug.Assert(genericFontFamily != GenericFontFamily.Unknown, 00531 "Construction of font with unknown fontfamily"); 00532 this.fontfamily = genericFontFamily.ToString(); 00533 this.genericFamily = genericFontFamily; 00534 this.size = size; 00535 this.style = style; 00536 } 00537 00541 public Font(string fontFamily, double size, FontStyle style) { 00542 Debug.Assert(fontFamily != "", "Empty fontfamily name"); 00543 this.fontfamily = fontFamily; 00544 this.genericFamily = GenericFontFamily.Unknown; 00545 this.size = size; 00546 this.style = style; 00547 } 00548 00552 public static Font SansSerif { 00553 get {return new Font(GenericFontFamily.SansSerif);} 00554 } 00555 00559 public static Font Serif { 00560 get {return new Font(GenericFontFamily.Serif);} 00561 } 00562 00566 public static Font Monospace { 00567 get {return new Font(GenericFontFamily.Monospace);} 00568 } 00569 00573 public override string ToString () 00574 { 00575 if(IsGeneric) { 00576 return String.Format("#{0}-{1}-{2}", GenericFamily, Style, Size); 00577 } 00578 else 00579 return String.Format("{0}-{1}-{2}", FontFamily, Style, Size); 00580 } 00581 } 00582 00586 public class WorldMatrix { 00587 private Matrix matrix; 00588 00592 public WorldMatrix() { 00593 matrix = new Matrix(); 00594 } 00595 00599 public WorldMatrix(WorldMatrix worldMatrix) { 00600 matrix = worldMatrix.matrix.Clone(); 00601 } 00602 00603 private WorldMatrix(Matrix m) { 00604 matrix = m; 00605 } 00606 00610 public WorldMatrix(double [,] m) { 00611 matrix = new Matrix((float)m[0,0], (float)m[0,1], (float)m[1,0], (float)m[1,1], 00612 (float)m[2,0], (float)m[2,1]); 00613 } 00614 00619 public WorldMatrix Rotate(double angleInDegree) { 00620 matrix.Rotate((float)angleInDegree, MatrixOrder.Append); 00621 return this; 00622 } 00623 00624 00629 public WorldMatrix Translate(Vector translateVector) { 00630 matrix.Translate((float)translateVector.X, (float)translateVector.Y, MatrixOrder.Append); 00631 return this; 00632 } 00633 00634 00640 public WorldMatrix Scale(double scaleInX, double scaleInY) { 00641 matrix.Scale((float) scaleInX, (float) scaleInY, MatrixOrder.Append); 00642 return this; 00643 } 00644 00649 public WorldMatrix Shear(Vector shearVector) { 00650 matrix.Scale((float) shearVector.X, (float) shearVector.Y, MatrixOrder.Append); 00651 return this; 00652 } 00653 00654 00661 public WorldMatrix AddTransformations (WorldMatrix wm) { 00662 matrix.Multiply(wm.matrix, MatrixOrder.Append); 00663 return this; 00664 } 00665 00670 public WorldMatrix InvertedMatrix { 00671 get { 00672 Matrix im = this.matrix.Clone(); 00673 im.Invert(); 00674 return new WorldMatrix(im); 00675 } 00676 } 00677 00681 public Position Transform(Position position) { 00682 PointF[] points = new PointF[]{new PointF((float)position.X, (float)position.Y)}; 00683 matrix.TransformPoints(points); 00684 return new Position(points[0].X, points[0].Y); 00685 } 00686 00691 public double [,] ToArrayMatrix() { 00692 return new double[3,3] { 00693 {matrix.Elements[0], matrix.Elements[1], 0.0}, 00694 {matrix.Elements[2], matrix.Elements[3], 0.0}, 00695 {matrix.Elements[4], matrix.Elements[5], 1.0} 00696 }; 00697 } 00698 00699 public override string ToString () 00700 { 00701 StringBuilder s = new StringBuilder(); 00702 for(int i=0; i<matrix.Elements.Length; i++) { 00703 s.AppendFormat("{0:G8} ", matrix.Elements[i]); 00704 if(i%2 == 1) 00705 s.Append("\n"); 00706 } 00707 return s.ToString(); 00708 } 00709 00710 } 00711 00717 public struct Parallelogram { 00718 Position [] vs; 00719 00724 public static Parallelogram FromSimpleRectangle (Position leftTop, Position rightBottom) { 00725 return new Parallelogram(leftTop, 00726 new Vector(rightBottom.X - leftTop.X, 0.0), 00727 new Vector(0.0, rightBottom.Y - leftTop.Y)); 00728 } 00729 00733 public Parallelogram(Position vertex, Vector v1, Vector v2) { 00734 vs = new Position[4]; 00735 vs[0] = vertex; 00736 vs[1] = vs[0] + v1; 00737 vs[2] = vs[1] + v2; 00738 vs[3] = vs[0] + v2; 00739 } 00740 00741 private Parallelogram(Position[] nvs) { 00742 vs = nvs; 00743 } 00744 00749 public Position Vertex(int i) { 00750 return vs[i]; 00751 } 00752 00756 public bool IsRectangle { 00757 get { 00758 return Math.Abs((vs[1]-vs[0]) * (vs[2]-vs[1])) 00759 < double.Epsilon; 00760 } 00761 } 00762 00767 public Parallelogram Transform(WorldMatrix m) { 00768 Position[] nvs = new Position[4]; 00769 for(int i=0; i<4; i++) 00770 nvs[i] = m.Transform(vs[i]); 00771 return new Parallelogram(nvs); 00772 } 00773 00777 public IEnumerable<Position> VertexEnumerator() { 00778 foreach(Position p in vs) 00779 yield return p; 00780 } 00781 } 00782 }