summaryrefslogtreecommitdiffstats
path: root/rasodmg/polygon.hh
blob: 76aa32deeff9077366ac93b2adb37cb422635092 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/*
* This file is part of rasdaman community.
*
* Rasdaman community is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rasdaman community is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rasdaman community.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see <http://www.rasdaman.org>
* or contact Peter Baumann via <baumann@rasdaman.com>.
/
/**
 * INCLUDE: polygon.hh
 *
 * MODULE:  rasodmg
 * CLASS:   r_Polygon
 *
 * COMMENTS:
 *		None
*/

#ifndef _R_POLYGON_
#define _R_POLYGON_

#include <iostream>
#include <vector>
#include <string>

#include "raslib/point.hh"
#include "raslib/minterval.hh"

class r_GMarray;

//@ManMemo: Module: {\bf rasodmg}

/*@Doc:

  The class r_Edge is used to represent edges of 2-D polygons
  represented in class r_Polygon. Edges cannot be modified. This does
  not make sense, as a polygon always has to consist out of connecting
  edges. Modifications should always be done on the polygon.
 
*/

/**
  * \ingroup Rasodmgs
  */
class r_Edge
{
public:
  /// constructor getting a 2-D start and end point.
  r_Edge(const r_Point& newStart, const r_Point& newEnd);

  /// retrieve 2-D start point of edge.
  const r_Point& getStart() const;

  /// retrieve 2-D end point of edge.
  const r_Point& getEnd() const;

  /// calculate inverse slope of the edge. Note: may throw exception due to division by 0.
  double getInvSlope() const;

  /// calculate slope of the edge. Note: may throw exception due to division by 0.
  double getSlope() const;

  /// retrieve x for a given y on a line with the slope of the edge. Calls getInvSlope().
  double getCurrX(r_Range y) const;

  /// retrieve y for a given x on a line with the slope of the edge. Calls getSlope().
  double getCurrY(r_Range x) const;

  /// print start and end point of the edge.
  void print_status( std::ostream& s = std::cout ) const;
  
  /// returns true if the edge is parallel to the first axis
  bool isHorizontal() const;
  
private:
  /// start point of the edge.
  r_Point start;

  /// end point of the edge.
  r_Point end;
};

/*@Doc:

  The class r_Polygon is used to represent 2-D polygons in
  RasDaMan. Polygons are always constructed by specifying a set of
  points. This class is mainly used for doing polygonal cutouts on
  r_Marray objects, it offers the relevant methods for that purpose.

  The construction of a r_Polygon with addPoint has to finish with a
  call to close(). A open polygon is not a legal polygon! Currently no
  exceptions are thrown if a polygon is open and methods besides
  addPointXY or close are called. The results are undefined, if the
  polygon is not closed.
 
*/

/**
  * \ingroup Rasodmgs
  */
class r_Polygon
{
public:

  /// FIXME current we support only 2 dimensional polygon
  static const r_Dimension polyPointDim;

  /// enum used to clasify one polygon
  enum r_Polygon_Type{
       UNKNOWN,
       CONCAVE,
       CONVEX
       };
       
  /// constructor to initialize polygon from a string
  r_Polygon(const char* init) throw (r_Error);
  
  /// constructor getting x and y of the first point in the polygon.
  r_Polygon(r_Range x, r_Range y);
  
  /// copy constructor 
  r_Polygon(const r_Polygon&);

  /// default constructor.
  r_Polygon();
  
  /// asignment opertor
  r_Polygon& operator=(const r_Polygon&);
  
  /// add a point to the polygon.
  void addPoint(const r_Point& newPoint) throw(r_Error);
  
  /// add a point to the polygon specifying x and y.
  void addPointXY(r_Range x, r_Range y) throw(r_Error);
  
  /// close a polygon after creation with addPointXY.
  void close();
  
  /// retrieve the set of all edges of the polygon.
  const std::vector<r_Edge>& getEdges() const throw(r_Error);
  
  /// determine the polygon type for an polygon in 2D
  r_Polygon::r_Polygon_Type detectPolygonType() const throw(r_Error);
  /**
      It is assumed that the polygon is simple (does not intersect itself or have holes)
      Returns UNKNOWN for incomputables eg: polygon with colinear points,  polygon with less then 3 points
  */
  
  /// retrieve a vector of all points in the polygon.
  std::vector<r_Point> getPoints() const throw(r_Error);
  /**
   Each point is connected with its successor. The last point is connected to the first one.
  */
  
  /// print all edges of the polygon.
  void print_status( std::ostream& s = std::cout ) const;
  
  /// Fill the 2-D array myArray according to the polygon.
  void fillMArray( r_GMarray& myArray, bool fillInside = false, const std::string& bgr = "") const throw(r_Error);
  /** The polygon has to be completely in the domain of the array. Should this not be the case, 
      then the polygon must be clipped according to the domain of the array. Filling is done 
      so that the data in the array is overwritten byte by byte with 0 which is not inside
      the polygon.
  */
  
  /// retrieve the bounding box of the polygon.
  r_Minterval getBoundingBox() const throw(r_Error);
  
  /// clip the polygon according to the bounding box specified in clipDom.
  void clip(const r_Minterval& clipDom) throw(r_Error);  
  /** Note that the r_Polygon object is modified! So after calling clip you will generally
      have a different polygon represented by your object. */
      
  /// scale the points of the polygon according to scaleFactor.
  void scale(const r_Point& origin, const r_Minterval& mddDom,
	     const r_Minterval& clipDom, const double& scaleFactor) throw(r_Error);
  /** This function is used when using a polygon to extract part of an image retrieved
      with r_Fast_Scale. The scaling is done like in r_Fast_Base_Scale::get_scaled_domain(). 
      origin is the point of origin for the scaling. mddDom is the domain of the MDD which
      will later be filled with the polygon. Problem is, that the domain of this MDD is
      currently not created by simply scaling the domain of the original MDD. Instead it
      is made sure that the origin of the scaled domain stays the same. clipDom is used
      to do the same when scaling the polygon, it contains the scaled domain of the MDD
      without shifting it to origin of the domain of the MDD before scaling. It is a
      bit complicated, I know. scaleFactor is trivially the scaleFactor used. */
      
  /// scale the points of the polygon according to scaleFactor.
  void scale(const r_Point& origin, const double& scaleFactor) throw(r_Error);
  /** This function is used used when we scale a polygon to extract part of an image retrieved
      with r_Fast_Scale. The scaling is done like in r_Fast_Base_Scale::get_scaled_domain(). 
      origin is the point of origin for the scaling. scaleFactor is the scale factor used. */

  /// mirrors a polygon along the y-axes point by point.
  void mirror(const r_Minterval& mddDom) throw(r_Error);
  /** The mirroring is done along the middle of mddDom. It is done like that to be coherent
      with the mirroring commonly done when inserting TIFF image, e.g. in insertlva.cc. */

  /// get "middle" point by averaging all x and y values.
  r_Point getMiddle() const throw(r_Error);

  /// "shrink" polygon by moving all points towards the middle by pixelCount pixels.
  void shrinkPoly(int pixelCount) throw(r_Error);

  ///  returns the number of edges
  int  countEdges() const;
  
  ///  returns the number of horizontal edges (used by polygon cut out)
  int  countHorizontalEdges() const;
   
private:

  /// check if the current point is the first point to close the polygon
  void checkFistPoint();

  /// clipping is done side by side. This enum is used to tell functions which side to clip.
  enum Side { 
    top, bottom, left, right
  };

  /// overwrite this with a polygon create from a vector of points.
  void fromPoints(const std::vector<r_Point>& newPoints) throw(r_Error);

  /// erase the area in myArray outside of the polygon for one scanline.
  void eraseLine( r_Range x1, r_Range x2, r_Range y, r_GMarray& myArray, const std::string& bgr ) const throw(r_Error);

  /// return the polygon clipped on the specified side as a list of points.
  std::vector<r_Point> clip1Side(const r_Minterval& b, r_Polygon::Side s);

  /// determine if a point is inside a bounding line on a certain side.
  bool inside(const r_Minterval& b, const r_Point& p, r_Polygon::Side s);

  /// intersect an edge with a bounding line on a certain side.
  r_Point intersect(const r_Minterval& b, const r_Edge& e, r_Polygon::Side s);

  /// flag if the polygon is closed.
  bool closed;

  /// flag if firstPoint has been set.
  bool firstPointSet;

  /// vector of all edges of the polygon.
  std::vector<r_Edge> edges;
  /// remember first point. Used when constructing the polygon.

  r_Point firstPoint;

  /// remember last added point. Used when constructing the polygon.
  r_Point currPoint;
};

extern std::ostream& operator<<( std::ostream& s, const r_Polygon& d );

// The following classes are STL function objects which can be used to make
// sorted collection of r_Edge. In the current implementation only the first
// one is needed.

/**
  * \ingroup Rasodmgs
  */
class EdgeSortCriterion
{
public:
  // This is needed for keeping a sorted set of edges (sorted by start coordinate y,
  // then start coordinate x).
  bool operator() (const r_Edge& e1, const r_Edge& e2) const {
    return e1.getStart()[1] < e2.getStart()[1] || 
      (!(e2.getStart()[1] < e1.getStart()[1]) && e1.getStart()[0] < e2.getStart()[0]);
  }
};

/**
  * \ingroup Rasodmgs
  */
class ActiveEdgeSortCriterion
{
public:
  // This is needed for keeping a sorted set of active edges (sorted by start coordinate x,
  // then start coordinate y).
  bool operator() (const r_Edge& e1, const r_Edge& e2) const {
    return e1.getStart()[0] < e2.getStart()[0] || 
      (!(e2.getStart()[0] < e1.getStart()[0]) && e1.getStart()[1] < e2.getStart()[1]);
  }
};

#endif