00001 #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
00002 #include <CGAL/Triangulation_euclidean_traits_xy_3.h>
00003 #include <CGAL/Delaunay_triangulation_2.h>
00004 #include <CGAL/Bbox_2.h>
00005 #include <CGAL/intersection_3_1.h>
00006
00007 #include <string>
00008 #include <iostream>
00009 #include <istream>
00010 #include <ostream>
00011 #include <fstream>
00012
00013 #include "parsecl.hpp"
00014
00015 struct K : CGAL::Exact_predicates_inexact_constructions_kernel {};
00016
00017 typedef K::Plane_3 Plane;
00018 typedef K::Line_3 Line;
00019 typedef CGAL::Bbox_2 BoundingBox;
00020
00021 typedef CGAL::Triangulation_euclidean_traits_xy_3<K> Gt;
00022 typedef CGAL::Delaunay_triangulation_2<Gt> Delaunay;
00023 typedef Delaunay::Point Point;
00024 typedef Delaunay::Point_iterator PointIterator;
00025 typedef Delaunay::Vertex_handle VertexHandle;
00026 typedef Delaunay::Face_handle FaceHandle;
00027 typedef Delaunay::Vertex_circulator VertexCirculator;
00028
00033 int main(int argc, char** argv) {
00034 using namespace Arak::Util;
00035
00036 CommandLine cl;
00037 CommandLine::Parameter<double>
00038 gamma("-g", "--gamma", "the gamma correction value", 1.0 / 0.45);
00039 cl.add(gamma);
00040 CommandLine::Parameter<int>
00041 widthSpec("-w", "--width", "the image width", -1);
00042 cl.add(widthSpec);
00043 CommandLine::Parameter<int>
00044 heightSpec("-h", "--height", "the image height", -1);
00045 cl.add(heightSpec);
00046 CommandLine::Parameter<int>
00047 depth("-d", "--depth", "the image depth (# gray values)", 256);
00048 cl.add(depth);
00049 CommandLine::Parameter<double>
00050 max("-min", "--min-intensity", "the surface value mapped to white", 0.0);
00051 cl.add(max);
00052 CommandLine::Parameter<double>
00053 min("-max", "--max-intensity", "the surface value mapped to black", 1.0);
00054 cl.add(min);
00055 CommandLine::Option
00056 linear("-l", "--linear-interpolation",
00057 "use linear instead of nearest-neighbor interpolation");
00058 cl.add(linear);
00059 CommandLine::Parameter<int>
00060 def("-n", "--nan",
00061 "the value to use for pixels outside the convex hull", 255);
00062 cl.add(def);
00063 CommandLine::Parameter<std::string>
00064 inputPath("-i", "--input",
00065 "the input file of point color estimates", std::string());
00066 cl.add(inputPath);
00067 CommandLine::Parameter<std::string>
00068 outputPath("-o", "--output", "the output PGM file", std::string());
00069 cl.add(outputPath);
00070 if (!cl.parse(argc, argv, std::cerr)) {
00071 cl.printUsage(std::cerr);
00072 exit(1);
00073 }
00074
00075
00076 std::istream* in = &std::cin;
00077 if (inputPath.supplied()) {
00078 in = new std::ifstream(inputPath.value().data());
00079 if (!in->good()) {
00080 std::cerr << "Error: cannot open file " << inputPath.value()
00081 << " for reading." << std::endl;
00082 exit(1);
00083 }
00084 }
00085 std::ostream* out = &std::cout;
00086 if (outputPath.supplied()) {
00087 out = new std::ofstream(outputPath.value().data());
00088 if (!out->good()) {
00089 std::cerr << "Error: cannot open file " << outputPath.value()
00090 << " for writing." << std::endl;
00091 exit(1);
00092 }
00093 }
00094
00095
00096 int* gcv = new int[depth.value()];
00097 gcv[0] = 0;
00098 for (int i = 1; i < depth.value(); i++) {
00099 double raw = double(i) / double(depth.value() - 1);
00100 double corr = pow(raw, gamma.value());
00101 gcv[i] = int(round(corr * double(depth.value() - 1)));
00102 }
00103
00104
00105 std::istream_iterator<Point> begin(*in);
00106 std::istream_iterator<Point> end;
00107 Delaunay dt;
00108 dt.insert(begin, end);
00109 std::cerr << "Read " << dt.number_of_vertices()
00110 << " points." << std::endl;
00111
00112
00113 VertexHandle infVertexHandle = dt.infinite_vertex();
00114 VertexCirculator circ = dt.incident_vertices(infVertexHandle);
00115 VertexCirculator first = dt.incident_vertices(infVertexHandle);
00116 Point p = circ->point();
00117 BoundingBox bbox(CGAL::to_double(p.x()), CGAL::to_double(p.y()),
00118 CGAL::to_double(p.x()), CGAL::to_double(p.y()));
00119 while (++circ != first) {
00120 p = circ->point();
00121 bbox = bbox + BoundingBox(CGAL::to_double(p.x()), CGAL::to_double(p.y()),
00122 CGAL::to_double(p.x()), CGAL::to_double(p.y()));
00123 }
00124 std::cerr << "Bounding box: " << bbox << std::endl;
00125
00126
00127
00128 int height, width;
00129 if (widthSpec.supplied() && heightSpec.supplied()) {
00130
00131 height = heightSpec.value();
00132 width = widthSpec.value();
00133 } else if (!widthSpec.supplied() && !heightSpec.supplied()) {
00134
00135
00136 int size = dt.number_of_vertices();
00137 double aspectRatio =
00138 (bbox.ymax() - bbox.ymin()) / (bbox.xmax() - bbox.xmin());
00139 width = int(round(sqrt(double(size) / aspectRatio)));
00140 height = int(aspectRatio * double(width));
00141 } else if (!heightSpec.supplied()) {
00142
00143
00144 width = widthSpec.value();
00145 double aspectRatio =
00146 (bbox.ymax() - bbox.ymin()) / (bbox.xmax() - bbox.xmin());
00147 height = int(aspectRatio * double(width));
00148 } else {
00149
00150
00151 height = heightSpec.value();
00152 double aspectRatio =
00153 (bbox.ymax() - bbox.ymin()) / (bbox.xmax() - bbox.xmin());
00154 width = int(double(height) / aspectRatio);
00155 }
00156
00157
00158 K::FT upd((bbox.xmax() - bbox.xmin()) / double(width));
00159 std::cerr << "Output resolution: " << width << "x" << height << std::endl;
00160
00161
00162 *out << "P2" << std::endl;
00163 *out << "# " << outputPath.value() << std::endl;
00164 *out << width << " " << height << std::endl;
00165 *out << (depth.value() - 1) << std::endl;
00166 K::FT y = bbox.ymax();
00167 int num_def = 0;
00168 FaceHandle fh = dt.infinite_face();
00169 for (int i = height - 1; i >= 0; i--) {
00170 K::FT x = bbox.xmin();
00171 for (int j = 0; j < width; j++) {
00172 Point q(x, y, K::FT(0));
00173 fh = dt.locate(q, fh);
00174 if ((fh == NULL) || dt.is_infinite(fh)) {
00175
00176 *out << def.value() << " ";
00177 num_def++;
00178 } else if (linear.supplied()) {
00179
00180
00181 Plane plane(fh->vertex(0)->point(),
00182 fh->vertex(1)->point(),
00183 fh->vertex(2)->point());
00184
00185 Line line(q, Point(x, y, K::FT(1.0)));
00186
00187 Point interp;
00188 CGAL::Object result = intersection(plane, line);
00189 assert(CGAL::assign(interp, result));
00190
00191 double value = CGAL::to_double(interp.z());
00192
00193 double intensity =
00194 (value - min.value()) / (max.value() - min.value());
00195 intensity = (intensity < 0.0) ? 0.0 : intensity;
00196 intensity = (intensity > 1.0) ? 1.0 : intensity;
00197
00198 *out << gcv[int(round(intensity * double(depth.value() - 1)))] << " ";
00199 } else {
00200
00201 Point p0 = fh->vertex(0)->point();
00202 Point p1 = fh->vertex(1)->point();
00203 Point p2 = fh->vertex(2)->point();
00204
00205
00206 double value;
00207 if (CGAL::compare_distance_to_point(q, p0, p1) ==
00208 CGAL::SMALLER) {
00209 if (CGAL::compare_distance_to_point(q, p0, p2) ==
00210 CGAL::SMALLER)
00211 value = CGAL::to_double(p0.z());
00212 else
00213 value = CGAL::to_double(p2.z());
00214 } else {
00215 if (CGAL::compare_distance_to_point(q, p1, p2) ==
00216 CGAL::SMALLER)
00217 value = CGAL::to_double(p1.z());
00218 else
00219 value = CGAL::to_double(p2.z());
00220 }
00221
00222 double intensity =
00223 (value - min.value()) / (max.value() - min.value());
00224 intensity = (intensity < 0.0) ? 0.0 : intensity;
00225 intensity = (intensity > 1.0) ? 1.0 : intensity;
00226
00227 *out << gcv[int(round(intensity * double(depth.value() - 1)))] << " ";
00228 }
00229 x += upd;
00230 }
00231 y -= upd;
00232 *out << std::endl;
00233 }
00234 *out << std::endl;
00235 out->flush();
00236
00237
00238 if (inputPath.supplied()) delete in;
00239 if (outputPath.supplied()) delete out;
00240
00241
00242 if (num_def > 0)
00243 std::cerr << "Warning: " << num_def
00244 << " pixel values defaulted to "
00245 << def.value() << std::endl;
00246
00247 return 0;
00248 }