1 /** 2 Scalar and integer 2D point types. 3 4 Copyright: Chris Jones 5 License: Boost Software License, Version 1.0 6 Authors: Chris Jones 7 */ 8 9 module dg2d.point; 10 11 import dg2d.scalar; 12 13 import std.algorithm: among; 14 15 /** 16 Integer 2D point. 17 18 This is typically used for specifying exact pixel coordinates. 19 */ 20 21 struct IPoint 22 { 23 int x = 0; 24 int y = 0; 25 26 /** Constructs a IPoint with the spefcified coordinates */ 27 28 this(int x, int y) 29 { 30 this.x = x; 31 this.y = y; 32 } 33 34 /** Constructs a IPoint with the spefcified coordinates */ 35 36 this(int[2] coords) 37 { 38 this.x = coords[0]; 39 this.y = coords[1]; 40 } 41 42 /** returns true if x and y are both zero */ 43 44 bool isZero() 45 { 46 return ((x == 0) && (y == 0)); 47 } 48 } 49 50 /** 51 2D Point. 52 53 Floating point 2D point. 54 */ 55 56 struct Point 57 { 58 Scalar x = 0; 59 Scalar y = 0; 60 61 /** Constructs a Point with the spefcified coordinates */ 62 63 this(Scalar x, Scalar y) 64 { 65 this.x = x; 66 this.y = y; 67 } 68 69 /** Constructs a Point with the spefcified coordinates */ 70 71 this(Scalar[2] coords) 72 { 73 this.x = coords[0]; 74 this.y = coords[1]; 75 } 76 77 /** returns true if x and y are both zero */ 78 79 bool isZero() 80 { 81 return ((x == 0) && (y == 0)); 82 } 83 84 /** operator overload for add, subtract or multiply. */ 85 86 Point opBinary(string op)(Point rhs) 87 if (op.among!("+", "-", "*")) 88 { 89 mixin("return Point(x "~op~" rhs.x, y "~op~"rhs.y);"); 90 } 91 92 /** operator overload for add, subtract or multiply. */ 93 94 Point opBinary(string op, T)(T rhs) 95 if (op.among!("+", "-", "*") && canConvertToScalar(T)) 96 { 97 mixin("return Point(x "~op~" rhs, y "~op~"rhs);"); 98 } 99 100 /** operator overload for add, subtract or multiply. */ 101 102 Point opBinary(string op, T)(T[2] rhs) 103 if (op.among!("+", "-", "*") && canConvertToScalar(T)) 104 { 105 mixin("return Point(x "~op~" rhs[0], y "~op~"rhs[1]);"); 106 } 107 } 108 109 /** Returns point offset by offset_x,offset_y */ 110 111 Point offset(Point point, Scalar offset_x, Scalar offset_y) 112 { 113 return Point(point.x+offset_x, point.y+offset_y); 114 } 115 116 /** Returns point scaled by scale_x,scale_y */ 117 118 Point scale(Point point, Scalar scale_x, Scalar scale_y) 119 { 120 return Point(point.x*scale_x, point.y*scale_y); 121 } 122 123 /** Returns point scaled by scale_x,scale_y but relative to focus_x,focus_y */ 124 125 Point scale(Point point, Scalar scale_x, Scalar scale_y, Scalar focus_x, Scalar focus_y) 126 { 127 return Point((point.x-focus_x)*scale_x+focus_x, (point.y-focus_y)*scale_y+focus_y); 128 } 129 130 // TODO - versions that take that pass in sin/cos values rather than call math funcs each time 131 // as they are very slow 132 133 /** Returns point rotated by the specified angle. angle is in degrees [0..360] */ 134 135 Point rotate(Point point, Scalar angle) 136 { 137 import std.math; 138 139 Scalar sina = cast(Scalar) sin(angle*2*PI/360); 140 Scalar cosa = cast(Scalar) cos(angle*2*PI/360); 141 return Point(point.x*cosa-point.y*sina, point.x*sina+point.y*cosa); 142 } 143 144 /** Returns point rotated by the specified angle around focus_x,focus_y. Angle 145 is in degrees [0..360] */ 146 147 Point rotate(Point point, Scalar angle, Scalar focus_x, Scalar focus_y) 148 { 149 import std.math; 150 151 Scalar sina = cast(Scalar) sin(angle*2*PI/360); 152 Scalar cosa = cast(Scalar) cos(angle*2*PI/360); 153 return Point( 154 (point.x-focus_x)*cosa-(point.y-focus_y)*sina+focus_x, 155 (point.x-focus_x)*sina+(point.y-focus_y)*cosa+focus_y 156 ); 157 } 158 159