1 /*
2  *******************************************************************************************
3  * Dgame (a D game framework) - Copyright (c) Randy Schütt
4  *
5  * This software is provided 'as-is', without any express or implied warranty.
6  * In no event will the authors be held liable for any damages arising from
7  * the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not claim
14  *    that you wrote the original software. If you use this software in a product,
15  *    an acknowledgment in the product documentation would be appreciated but is
16  *    not required.
17  *
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  *
21  * 3. This notice may not be removed or altered from any source distribution.
22  *******************************************************************************************
23  */
24 module Dgame.Math.Circle;
25 
26 private:
27 
28 import derelict.sdl2.sdl;
29 
30 import Dgame.Math.Vector2;
31 
32 import std.math: sqrt;
33 
34 
35 public:
36 
37 /**
38  * Circle defines a circle structure.
39  *
40  * Author: Leonardo Tada
41  */
42 struct Circle {
43 
44     /**
45      * The x coordinate
46      */
47     int x = 0;
48     /**
49      * The y coordinates
50      */
51     int y = 0;
52     /**
53      * The radius
54      */
55     uint radius;
56 
57     /**
58      * CTor
59      */
60     @nogc
61     this(int x, int y, uint radius) pure nothrow {
62         this.x = x;
63         this.y = y;
64         this.radius  = radius;
65     }
66 
67     /**
68      * Supported operations: +, -, *, /, %
69      */
70     @nogc
71     Circle opBinary(string op)(const Circle circle) const pure nothrow {
72         switch (op) {
73             case "+":
74             case "-":
75             case "*":
76             case "/":
77             case "%":
78                 mixin("return Circle(this.x " ~ op ~ " circle.x,
79                               this.y " ~ op ~ " circle.y,
80                               this.radius " ~ op ~ " circle.radius;");
81             default:
82                 assert(0, "Unsupported Operation: " ~ op);
83         }
84     }
85 
86     /**
87      * Collapse this Circle. Means that the radius is set to 0.
88      */
89     @nogc
90     void collapse() pure nothrow {
91         this.radius = 0;
92     }
93 
94     /**
95      * Checks if this Circle is empty (if it's collapsed) with SDL_RectEmpty.
96      */
97     @nogc
98     bool isEmpty() const pure nothrow {
99         return this.radius == 0;
100     }
101 
102     // /**
103     //  * Checks whether this Circle contains the given coordinates.
104     //  */
105     // @nogc
106     // bool contains(const Vector2i vec) const pure nothrow {
107     //     return this.contains(vec.x, vec.y);
108     // }
109 
110     // /**
111     //  * Checks whether this Circle contains the given coordinates.
112     //  */
113     // @nogc
114     // bool contains(int x, int y) const pure nothrow {
115     //     // TODO
116     // }
117 
118     /**
119      * opEquals: compares two rectangles on their coordinates and their size (but not explicit type).
120      */
121     @nogc
122     bool opEquals(const Circle circle) const pure nothrow {
123         return this.x == circle.x && this.y == circle.y && this.radius == circle.radius;
124     }
125 
126     /**
127      * Checks whether this Circle intersects with an other.
128      * If, and the parameter 'overlap' isn't null,
129      * the colliding circle is stored there.
130      */
131     @nogc
132     bool intersects(const Circle circle, Circle* overlap = null) const {
133         immutable Vector2i center1 = getCenter();
134         immutable Vector2i center2 = circle.getCenter();
135         immutable int dx = center1.x - center2.x;
136         immutable int dy = center1.y - center2.y;
137         immutable float distance = sqrt(cast(float)dx * dx + dy * dy);
138 
139         return distance < this.radius + circle.radius;
140         // TODO stored
141     }
142 
143     /**
144      * Replace the current size.
145      */
146     @nogc
147     void setRadius(uint radius) pure nothrow {
148         this.radius = radius;
149     }
150 
151     /**
152      * Returns the current radius
153      */
154     @nogc
155     uint getRadius() const pure nothrow {
156         return this.radius;
157     }
158 
159     /**
160      * Increase current size.
161      */
162     @nogc
163     void increase(int radius) pure nothrow {
164         this.radius += radius;
165     }
166 
167     /**
168      * Set a new position with coordinates.
169      */
170     @nogc
171     void setPosition(int x, int y) pure nothrow {
172         this.x = x;
173         this.y = y;
174     }
175 
176     /**
177      * Set a new position with a vector.
178      */
179     @nogc
180     void setPosition(const Vector2i position) pure nothrow {
181         this.setPosition(position.x, position.y);
182     }
183 
184     /**
185      * Returns the current position as Vector2
186      */
187     @nogc
188     Vector2i getPosition() const pure nothrow {
189         return Vector2i(this.x, this.y);
190     }
191 
192     /**
193      * Move the object.
194      */
195     @nogc
196     void move(const Vector2i vec) pure nothrow {
197         this.move(vec.x, vec.y);
198     }
199 
200     /**
201      * Move the object.
202      */
203     @nogc
204     void move(int x, int y) pure nothrow {
205         this.x += x;
206         this.y += y;
207     }
208 
209     /**
210      * Returns the center position of this Circle
211      */
212     @nogc
213     Vector2i getCenter() const pure nothrow {
214         return Vector2i(this.x + this.radius, this.y + this.radius);
215     }
216 }