38#include "DGtal/base/Common.h"
39#include "DGtal/helpers/StdDefs.h"
42#include "DGtal/io/writers/GenericWriter.h"
43#include "DGtal/images/ImageSelector.h"
44#include "DGtal/io/boards/Board2D.h"
47#include "DGtal/io/readers/PointListReader.h"
103std::pair<Z2i::Point, Z2i::Point > getBoundingBox(
const std::vector<Z2i::Point>& vecPts);
104std::vector<Z2i::Point> GaussDigization(
const std::vector<Z2i::Point>& polygon);
106int main(
int argc,
char** argv )
111 std::string inputFileName;
112 std::string outputFileName=
"result.pgm";
114 app.description(
"compute the set of integer points inside the input polyline.\n Basic example:\n \t 2dSimplePolygonDigitizer -i inputPolyline.sdp -o contourDisplay.pgm");
115 app.add_option(
"-i,--input,1", inputFileName,
"Input filename (freeman chain of sdp)." )
117 ->check(CLI::ExistingFile);
118 app.add_option(
"-o,--output,2", outputFileName,
"Output filename");
120 app.get_formatter()->column_width(40);
121 CLI11_PARSE(app, argc, argv);
124 std::string inputExt = inputFileName.substr(inputFileName.find_last_of(
".")+1);
125 if(inputExt !=
"sdp"){
126 trace.error() <<
"input file should be sdp file" << std::endl;
130 std::vector<Z2i::Point> poly = PointListReader<Z2i::Point>::getPointsFromFile(inputFileName);
131 std::vector<Z2i::Point> gd = GaussDigization(poly);
133 std::string outputExt = outputFileName.substr(outputFileName.find_last_of(
".")+1);
134 std::string outputBaseName = outputFileName.substr(0, outputFileName.find_last_of(
"."));
136 if(outputExt ==
"pgm") {
138 std::pair<Z2i::Point, Z2i::Point> bb = getBoundingBox(gd);
139 typedef ImageSelector <Z2i::Domain, unsigned char>::Type Image;
140 Z2i::Point p1 = bb.first-Z2i::Point(1,1);
141 Z2i::Point p2 = bb.second+Z2i::Point(1,1);
142 Image image(Z2i::Domain(p1,p2));
143 for(std::vector<Z2i::Point>::const_iterator it=gd.begin(); it!=gd.end(); it++) {
144 Z2i::Point p ((*it)[0],(*it)[1]);
145 image.setValue(p,255);
147 PGMWriter<Image>::exportPGM(outputFileName,image);
151 outputFileName = outputBaseName +
".svg";
152 DGtal::Board2D board;
153 board << DGtal::SetMode(
"PointVector",
"Both");
154 for(std::vector<Z2i::Point>::const_iterator it=gd.begin(); it!=gd.end(); it++) {
157 board.setPenColor(DGtal::Color::Red);
158 board.setLineWidth(2);
159 for(
size_t it=0; it<poly.size()-1; it++) {
160 DGtal::Z2i::RealPoint p1 (poly.at(it)[0],poly.at(it)[1]);
161 DGtal::Z2i::RealPoint p2 (poly.at(it+1)[0],poly.at(it+1)[1]);
162 board.drawLine(p1[0],p1[1],p2[0],p2[1]);
164 DGtal::Z2i::RealPoint p1 (poly.front()[0],poly.front()[1]);
165 DGtal::Z2i::RealPoint p2 (poly.back()[0],poly.back()[1]);
166 board.drawLine(p1[0],p1[1],p2[0],p2[1]);
168 board.saveSVG(outputFileName.c_str());
175std::pair<Z2i::Point, Z2i::Point > getBoundingBox(
const std::vector<Z2i::Point>& vecPts) {
176 int minX = vecPts.at(0)[0];
177 int maxX = vecPts.at(0)[0];
178 int minY = vecPts.at(0)[1];
179 int maxY = vecPts.at(0)[1];
181 for(
size_t it=1; it<vecPts.size(); it++) {
182 int x = vecPts.at(it)[0];
183 int y = vecPts.at(it)[1];
184 if(minX > x) minX = x;
185 if(maxX < x) maxX = x;
186 if(minY > y) minY = y;
187 if(maxY < y) maxY = y;
189 Z2i::Point tl (minX,minY);
190 Z2i::Point rb (maxX,maxY);
191 return std::make_pair(tl,rb);
199 return v1 > v2 ? v1 : v2;
203 return v1 > v2 ? v2 : v1;
205template<
typename TPo
int>
206bool onSegment(TPoint p, TPoint q, TPoint r)
208 if (q[0] <= max(p[0], r[0]) && q[0] >= min(p[0], r[0]) && q[1] <= max(p[1], r[1]) && q[1] >= min(p[1], r[1]))
218template<
typename TPo
int>
219int orientation(TPoint p, TPoint q, TPoint r)
221 int val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
222 if (val == 0)
return 0;
223 return (val > 0)? 1: 2;
228template<
typename TPo
int>
229bool doIntersect(TPoint p1, TPoint q1, TPoint p2, TPoint q2)
233 int o1 = orientation(p1, q1, p2);
234 int o2 = orientation(p1, q1, q2);
235 int o3 = orientation(p2, q2, p1);
236 int o4 = orientation(p2, q2, q1);
239 if (o1 != o2 && o3 != o4)
244 if (o1 == 0 && onSegment(p1, p2, q1))
return true;
247 if (o2 == 0 && onSegment(p1, q2, q1))
return true;
250 if (o3 == 0 && onSegment(p2, p1, q2))
return true;
253 if (o4 == 0 && onSegment(p2, q1, q2))
return true;
259template<
typename TPo
int>
260TPoint findDirection(
const std::vector<TPoint>& polygon, TPoint p, TPoint d1, TPoint d2 )
267 for(
size_t it=0; it<polygon.size(); it++) {
269 if(polygon.at(it)==p)
274 if(orientation(p, polygon.at(it), d)==0) {
275 d[0] = (d[0] + d2[0])/2;
276 d[1] = (d[1] + d2[1])/2;
286template<
typename TPo
int>
287bool isInsidePolygon(
const std::vector<TPoint>& polygon, TPoint p)
289 int n = polygon.size();
291 if (n < 3)
return false;
295 TPoint extreme1 (p[0], INT_MAX/1e6);
296 TPoint extreme2 (INT_MAX/1e6, p[1]);
297 TPoint extreme = findDirection(polygon, p, extreme1, extreme2);
303 int count = 0, i = 0;
310 if (doIntersect(polygon[i], polygon[next], p, extreme))
315 if (orientation(polygon[i], p, polygon[next]) == 0)
316 return onSegment(polygon[i], p, polygon[next]);
328std::vector<Z2i::Point> GaussDigization(
const std::vector<Z2i::Point>& polygon)
330 typedef Z2i::Point TPoint;
331 std::vector<TPoint> gd;
332 std::pair<TPoint, TPoint> bb = getBoundingBox(polygon);
333 int minx = int(bb.first[0])-1;
334 int miny = int(bb.first[1])-1;
335 int maxx = int(bb.second[0])+1;
336 int maxy = int(bb.second[1])+1;
337 for(
int x = minx; x<maxx; x++) {
338 for(
int y = miny; y<maxy; y++) {
340 bool ok = isInsidePolygon<TPoint>(polygon,p);
342 TPoint pi(p[0],p[1]);