1 /******************************************************************************
2  *  Warmux is a convivial mass murder game.
3  *  Copyright (C) 2001-2011 Warmux Team.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18  ******************************************************************************
19  * Polygon Generator. Generate various polygon shape on demand (including random one).
20  *****************************************************************************/
21 
22 #include <stdlib.h>
23 #include "graphic/polygon.h"
24 #include "graphic/polygon_generator.h"
25 #include "network/randomsync.h"
26 #include "tool/affine_transform.h"
27 
28 const int PolygonGenerator::MIN_SPACE_BETWEEN_POINT = 50;
29 
GenerateCircle(Double diameter,int nb_point)30 Polygon * PolygonGenerator::GenerateCircle(Double diameter, int nb_point)
31 {
32   return PolygonGenerator::GenerateDentedCircle(diameter, nb_point, ZERO);
33 }
34 
GenerateRectangle(Double width,Double height)35 Polygon * PolygonGenerator::GenerateRectangle(Double width, Double height)
36 {
37   Polygon * tmp = new Polygon();
38   tmp->AddPoint(Point2d( width * ONE_HALF,  height * ONE_HALF));
39   tmp->AddPoint(Point2d( width * ONE_HALF, -height * ONE_HALF));
40   tmp->AddPoint(Point2d(-width * ONE_HALF, -height * ONE_HALF));
41   tmp->AddPoint(Point2d(-width * ONE_HALF,  height * ONE_HALF));
42   return tmp;
43 }
44 
GenerateRectangle(const Point2d & orig,const Point2d & size)45 Polygon * PolygonGenerator::GenerateRectangle(const Point2d & orig, const Point2d & size)
46 {
47   Polygon * tmp = new Polygon();
48   tmp->AddPoint(Point2d(orig.x + size.x, orig.y + size.y));
49   tmp->AddPoint(Point2d(orig.x + size.x, orig.y));
50   tmp->AddPoint(Point2d(orig.x,          orig.y));
51   tmp->AddPoint(Point2d(orig.x,          orig.y + size.y));
52   return tmp;
53 }
54 
GenerateRectangle(const Rectanglei & r)55 Polygon * PolygonGenerator::GenerateRectangle(const Rectanglei & r)
56 {
57   return PolygonGenerator::GenerateRectangle(r.GetPosition(), r.GetSize());
58 }
59 
GenerateRectangle(const Point2i & orig,const Point2i & size)60 Polygon * PolygonGenerator::GenerateRectangle(const Point2i & orig, const Point2i & size)
61 {
62   return PolygonGenerator::GenerateRectangle((Point2d)orig, (Point2d)size);
63 }
64 
GenerateDentedCircle(Double diameter,int nb_point,Double rand_offset)65 Polygon * PolygonGenerator::GenerateDentedCircle(Double diameter, int nb_point, Double rand_offset)
66 {
67   Polygon * tmp = new Polygon();
68   AffineTransform2D trans = AffineTransform2D();
69   Point2d top;
70   for(int i = 0; i < nb_point; i++) {
71     top = Point2d(ZERO, (diameter + RandomSync().GetDouble(-rand_offset, rand_offset)) * ONE_HALF);
72     trans.SetRotation((TWO_PI * -i) / nb_point);
73     tmp->AddPoint(trans * top);
74   }
75   return tmp;
76 }
77 
GenerateRoundedRectangle(Double width,Double height,Double edge)78 Polygon * PolygonGenerator::GenerateRoundedRectangle(Double width, Double height, Double edge)
79 {
80   Polygon * tmp = new Polygon();
81   Double edge_vector = edge * ONE_HALF;
82   tmp->AddBezierCurve(Point2d(-width * ONE_HALF + edge, -height * ONE_HALF),
83                       Point2d(-edge_vector, 0),
84                       Point2d(0, -edge_vector),
85                       Point2d(-width * ONE_HALF, -height * ONE_HALF + edge));
86   tmp->AddBezierCurve(Point2d(-width * ONE_HALF, height * ONE_HALF - edge),
87                       Point2d(0, edge_vector),
88                       Point2d(-edge_vector, 0),
89                       Point2d(-width * ONE_HALF + edge, height * ONE_HALF));
90   tmp->AddBezierCurve(Point2d(width * ONE_HALF - edge, height * ONE_HALF),
91                       Point2d(edge_vector, 0),
92                       Point2d(0, edge_vector),
93                       Point2d(width * ONE_HALF, height * ONE_HALF - edge));
94   tmp->AddBezierCurve(Point2d(width * ONE_HALF, -height * ONE_HALF + edge),
95                       Point2d(0, -edge_vector),
96                       Point2d(edge_vector, 0),
97                       Point2d(width * ONE_HALF - edge, -height * ONE_HALF));
98   return tmp;
99 }
100 
GenerateRandomShape()101 Polygon * PolygonGenerator::GenerateRandomShape()
102 {
103   Double height = RandomSync().GetDouble(400.0, 600.0);
104   Double width  = RandomSync().GetDouble(400.0, 2000.0);
105   return GenerateRandomTrapeze(width, height, RandomSync().GetDouble(10.0, 15.0), RandomSync().GetDouble(10.0, 15.0),
106                                RandomSync().GetSign() * RandomSync().GetDouble(0.5, 1.0));
107 }
108 
GenerateRandomTrapeze(const Double width,const Double height,const Double x_rand_offset,const Double y_rand_offset,const Double coef)109 Polygon * PolygonGenerator::GenerateRandomTrapeze(const Double width, const Double height,
110                                                   const Double x_rand_offset, const Double y_rand_offset,
111                                                   const Double coef)
112 {
113   Double upper_width, lower_width, upper_offset, lower_offset;
114   int number_of_bottom_point, number_of_side_point;
115   // XXX Unused !?
116   // int number_of_upper_point;
117   Polygon * tmp = new Polygon();
118   number_of_side_point = 1 + (int)RandomSync().GetDouble((height / FOUR) / MIN_SPACE_BETWEEN_POINT,
119                                      height / MIN_SPACE_BETWEEN_POINT);
120   if(coef > ZERO) {
121     upper_width = width;
122     lower_width = width * coef;
123     upper_offset = RandomSync().GetDouble(ZERO, width - lower_width);
124     lower_offset = ZERO;
125   } else {
126     upper_width = - width * coef;
127     lower_width = width;
128     upper_offset = ZERO;
129     lower_offset = RandomSync().GetDouble(ZERO, width - upper_width);
130   }
131   // XXX Unused !?
132   //number_of_upper_point = RandomSync().GetInt(1 + (int)((upper_width * 0.25) / MIN_SPACE_BETWEEN_POINT),
133   //                                       (int)(upper_width / MIN_SPACE_BETWEEN_POINT));
134   number_of_bottom_point = RandomSync().GetInt(1 + (int)((lower_width / FOUR) / MIN_SPACE_BETWEEN_POINT),
135                                           (int)((coef * lower_width) / MIN_SPACE_BETWEEN_POINT));
136   tmp->AddRandomCurve(Point2d(upper_offset, ZERO), Point2d(lower_offset, height),
137                       x_rand_offset, y_rand_offset, number_of_side_point, false, false);
138   tmp->AddRandomCurve(Point2d(lower_offset, height), Point2d(lower_offset + lower_width, height),
139                       x_rand_offset, y_rand_offset, number_of_bottom_point, false, false);
140   tmp->AddRandomCurve(Point2d(lower_offset + lower_width, height), Point2d(upper_offset + upper_width, ZERO),
141                       x_rand_offset, y_rand_offset, number_of_side_point, false, false);
142   tmp->AddRandomCurve(Point2d(upper_offset + upper_width, ZERO), Point2d(upper_offset, ZERO),
143                       x_rand_offset, y_rand_offset, number_of_side_point, false, false);
144   return tmp;
145 }
146 
GeneratePie(Double diameter,int nb_point,Double angle,Double angle_offset)147 Polygon * PolygonGenerator::GeneratePie(Double diameter, int nb_point, Double angle, Double angle_offset)
148 {
149   Polygon * tmp = new Polygon();
150   AffineTransform2D trans = AffineTransform2D();
151   Point2d top;
152   for(int i = 0; i < nb_point; i++) {
153     top = Point2d(ZERO, diameter * ONE_HALF);
154     trans.SetRotation(angle_offset + ((i * angle) / nb_point));
155     tmp->AddPoint(trans * top);
156   }
157   if(angle < TWO_PI)
158     tmp->AddPoint(Point2d(0, 0));
159   return tmp;
160 }
161 
GeneratePartialTorus(Double diameter,Double min_diameter,int nb_point,Double angle,Double angle_offset)162 Polygon * PolygonGenerator::GeneratePartialTorus(Double diameter, Double min_diameter, int nb_point, Double angle, Double angle_offset)
163 {
164   if(diameter < min_diameter) {
165     Double tmp = diameter;
166     diameter = min_diameter;
167     min_diameter = tmp;
168   }
169   Polygon * tmp = new Polygon();
170   AffineTransform2D trans = AffineTransform2D();
171   Point2d top = Point2d(0, diameter*ONE_HALF);
172   for(int i = 0; i < nb_point; i++) {
173     trans.SetRotation(angle_offset + ((i * angle) / (nb_point - 1)));
174     tmp->AddPoint(trans * top);
175   }
176   top = Point2d(0, min_diameter*ONE_HALF);
177   for(int i = nb_point - 1; i >= 0; i--) {
178     trans.SetRotation(angle_offset + ((i * angle) / (nb_point - 1)));
179     tmp->AddPoint(trans * top);
180   }
181   return tmp;
182 }
183 
GenerateDecoratedBox(Double width,Double height)184 DecoratedBox * PolygonGenerator::GenerateDecoratedBox(Double width, Double height)
185 {
186   DecoratedBox * tmp = new DecoratedBox(width, height);
187 
188   return tmp;
189 }
190