// Copyright (c) 1997,1998,1999,2000,2001 // Utrecht University (The Netherlands), // ETH Zurich (Switzerland), // INRIA Sophia-Antipolis (France), // Max-Planck-Institute Saarbruecken (Germany), // and Tel-Aviv University (Israel). All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 3 of the License, // or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: LGPL-3.0+ // // // Author(s) : Andreas Fabri, Sylvain Pion #ifndef CGAL_GEOMVIEW_STREAM_H #define CGAL_GEOMVIEW_STREAM_H #include #ifdef CGAL_USE_GEOMVIEW #include #include #include #include #include #include #include #include #include #include #include namespace CGAL { class CGAL_EXPORT Geomview_stream { public: Geomview_stream(const Bbox_3 &bbox = Bbox_3(0,0,0, 1,1,1), const char *machine = NULL, const char *login = NULL); ~Geomview_stream(); Geomview_stream &operator<<(const Color &c); Geomview_stream &operator<<(const std::string & s); Geomview_stream &operator<<(int i); Geomview_stream &operator<<(unsigned int i); Geomview_stream &operator<<(long i); Geomview_stream &operator<<(unsigned long i); Geomview_stream &operator<<(double d); template < class InputIterator > void draw_triangles(InputIterator begin, InputIterator end); Geomview_stream &operator>>(char *expr); void clear(); void look_recenter(); void set_bg_color(const Color &c); Color get_vertex_color() const; Color get_edge_color() const; Color get_face_color() const; Color set_vertex_color(const Color&); Color set_edge_color(const Color&); Color set_face_color(const Color&); double vcr() const; double vcg() const; double vcb() const; double ecr() const; double ecg() const; double ecb() const; double fcr() const; double fcg() const; double fcb() const; double get_vertex_radius() const { return radius; } double set_vertex_radius(double r) { std::swap(r, radius); return r; } int get_line_width() const { return line_width; } int set_line_width(int w) { std::swap(w, line_width); return w; } bool set_wired(bool b) { std::swap(b, wired_flag); return b; } bool get_wired() const { return wired_flag; } bool set_echo(bool b) { std::swap(b, echo_flag); return b; } bool get_echo() const { return echo_flag; } bool set_raw(bool b) { std::swap(b, raw_flag); return b; } bool get_raw() const { return raw_flag; } bool set_trace(bool b) { std::swap(b, trace_flag); return b; } bool get_trace() const { return trace_flag; } void trace(const std::string s) const { if (get_trace()) std::cerr << s; } void trace(double d) const { if (get_trace()) std::cerr << d << ' '; } void trace(int i) const { if (get_trace()) std::cerr << i << ' '; } void trace(unsigned int i) const { if (get_trace()) std::cerr << i << ' '; } bool set_binary_mode(bool b = true) { std::swap(b, binary_flag); return b; } bool set_ascii_mode(bool b = true) { return !set_binary_mode(!b); } bool get_binary_mode() const { return binary_flag; } bool get_ascii_mode() const { return !binary_flag; } std::string get_new_id(const std::string & s); const Bbox_3 & get_bbox() { return bb; } void pickplane() { pickplane(get_bbox()); } static char* nth(char* s, int count); static void parse_point(const char* pickpoint, double &x, double &y, double &z, double &w); private: void setup_geomview(const char *machine, const char *login); void frame(const Bbox_3 &bbox); void pickplane(const Bbox_3 &bbox); Bbox_3 bb; Color vertex_color, edge_color, face_color; bool wired_flag; // decides if we draw surfaces or edges. bool echo_flag; // decides if we echo the point we get back to Geomview. bool raw_flag; // decides if we output footers and headers. bool trace_flag; // makes operator<<() write a trace on cerr. bool binary_flag; // makes operator<<() write binary format int line_width; // width of edges double radius; // radius of vertices int in, out; // file descriptors for input and output pipes int pid; // the geomview process identification std::map id; // used to get a unique ID per type. }; // Factorize code for Point_2 and Point_3. template < class FT > void output_point(Geomview_stream &gv, const FT &x, const FT &y, const FT &z) { bool ascii_bak = true; // the initialization value shuts up the compiler. if (!gv.get_raw()) { ascii_bak = gv.set_ascii_mode(); gv << "(geometry " << gv.get_new_id("P") << " {appearance {linewidth 5 material {edgecolor " << gv.vcr() << gv.vcg() << gv.vcb() << "}}{SKEL 1 1 "; } gv << CGAL::to_double(x) << CGAL::to_double(y) << CGAL::to_double(z); if (!gv.get_raw()) { gv << "1 0\n}})"; gv.set_ascii_mode(ascii_bak); } } #if defined CGAL_POINT_2_H && \ !defined CGAL_GV_OUT_POINT_2_H #define CGAL_GV_OUT_POINT_2_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Point_2 &p) { typename R::FT zero(0); output_point(gv, p.x(), p.y(), zero); return gv; } #endif #if defined CGAL_POINT_3_H && \ !defined CGAL_GV_OUT_POINT_3_H #define CGAL_GV_OUT_POINT_3_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Point_3 &p) { output_point(gv, p.x(), p.y(), p.z()); return gv; } #endif // The following code is the same for Segment_2 and Segment_3. template < class Segment > void output_segment(Geomview_stream &gv, const Segment &segment) { bool ascii_bak = gv.set_ascii_mode(); gv << "(geometry " << gv.get_new_id("Seg") << " {appearance {linewidth " << gv.get_line_width() << "}{VECT " << 1 << 2 << 1 // 1 polyline, two vertices, 1 color << 2 // the first polyline contains 2 vertices << 1; // and it has 1 color // here are start and end points bool raw_bak = gv.set_raw(true); gv << segment.source() << segment.target(); gv.set_raw(raw_bak); // and the color of the segment and its opaqueness gv << gv.ecr() << gv.ecg() << gv.ecb() << 1.0 << "}})"; gv.set_ascii_mode(ascii_bak); } #if defined CGAL_SEGMENT_2_H && \ !defined CGAL_GV_OUT_SEGMENT_2_H #define CGAL_GV_OUT_SEGMENT_2_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Segment_2 &segment) { output_segment(gv, segment); return gv; } #endif #if defined CGAL_SEGMENT_3_H && \ !defined CGAL_GV_OUT_SEGMENT_3_H #define CGAL_GV_OUT_SEGMENT_3_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Segment_3 &segment) { output_segment(gv, segment); return gv; } #endif // The following code is the same for Triangle_2 and Triangle_3. template < class Triangle > void output_triangle(Geomview_stream &gv, const Triangle &triangle) { bool ascii_bak = gv.set_ascii_mode(); gv << "(geometry " << gv.get_new_id("Tr") << " {appearance {+edge material {edgecolor " << gv.ecr() << gv.ecg() << gv.ecb() << " } shading constant}{ "; gv.set_binary_mode(); // it's a planar polygon gv << "OFF BINARY\n" // it has 3 vertices, 1 face and 3 edges << 3 << 1 << 3; bool raw_bak = gv.set_raw(true); for(int i=0; i<3; i++) gv << triangle[i]; gv.set_raw(raw_bak); // the face gv << 3 << 0 << 1 << 2 << 4 << gv.fcr() << gv.fcg() << gv.fcb() << 1.0 << "}})"; gv.set_ascii_mode(ascii_bak); } // Draws a set of triangles as OFF format (it's faster than one by one). template < class InputIterator > void Geomview_stream::draw_triangles(InputIterator begin, InputIterator end) { typedef typename std::iterator_traits::value_type Triangle; typedef typename Kernel_traits::Kernel Kernel; typedef typename Kernel::Point_3 Point; typedef typename Kernel::Less_xyz_3 Comp; // We first copy everything in a vector to only require an InputIterator. std::vector triangles(begin, end); typedef typename std::vector::const_iterator Tit; // Put the points in a map and a vector. // The index of a point in the vector is the value associated // to it in the map. typedef std::map Point_map; Point_map point_map(Kernel().less_xyz_3_object()); std::vector points; for (Tit i = triangles.begin(); i != triangles.end(); ++i) for (int j = 0; j < 3; ++j) if (point_map.insert(typename Point_map::value_type(i->vertex(j), points.size())).second) points.push_back(i->vertex(j)); bool ascii_bak = get_ascii_mode(); bool raw_bak = set_raw(true); // Header. set_binary_mode(); (*this) << "(geometry " << get_new_id("triangles") << " {appearance {}{ OFF BINARY\n" << points.size() << triangles.size() << 0; // Points coordinates. std::copy(points.begin(), points.end(), Ostream_iterator(*this)); // Triangles vertices indices. for (Tit tit = triangles.begin(); tit != triangles.end(); ++tit) { (*this) << 3; for (int j = 0; j < 3; ++j) (*this) << point_map[tit->vertex(j)]; (*this) << 0; // without color. } // Footer. (*this) << "}})"; set_raw(raw_bak); set_ascii_mode(ascii_bak); } #if defined CGAL_TRIANGLE_2_H && \ !defined CGAL_GV_OUT_TRIANGLE_2_H #define CGAL_GV_OUT_TRIANGLE_2_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Triangle_2 &triangle) { output_triangle(gv, triangle); return gv; } #endif #if defined CGAL_TRIANGLE_3_H && \ !defined CGAL_GV_OUT_TRIANGLE_3_H #define CGAL_GV_OUT_TRIANGLE_3_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Triangle_3 &triangle) { output_triangle(gv, triangle); return gv; } #endif #if defined CGAL_TETRAHEDRON_3_H && \ !defined CGAL_GV_OUT_TETRAHEDRON_3_H #define CGAL_GV_OUT_TETRAHEDRON_3_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Tetrahedron_3 &t) { bool ascii_bak = gv.set_ascii_mode(); gv << "(geometry " << gv.get_new_id("Tetra") << " {appearance {}{ "; gv.set_binary_mode(); gv << "OFF BINARY\n" // it has 4 vertices, 4 face and 6 edges << 4 << 4 << 6 ; // the vertices bool raw_bak = gv.set_raw(true); for(int i=0; i<4; i++) gv << t[i]; gv.set_raw(raw_bak); // the faces double r = gv.fcr(), g = gv.fcg(), b = gv.fcb(); gv << 3 << 0 << 1 << 2 << 4 << r << g << b << 1.0 << 3 << 3 << 0 << 1 << 4 << r << g << b << 1.0 << 3 << 3 << 1 << 2 << 4 << r << g << b << 1.0 << 3 << 3 << 0 << 2 << 4 << r << g << b << 1.0 << "}})"; gv.set_ascii_mode(ascii_bak); return gv; } #endif #if defined CGAL_SPHERE_3_H && \ !defined CGAL_GV_OUT_SPHERE_3_H #define CGAL_GV_OUT_SPHERE_3_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Sphere_3 &S) { bool ascii_bak = gv.set_ascii_mode(); gv << "(geometry " << gv.get_new_id("Sph") << " {appearance {+edge material {edgecolor " << gv.ecr() << gv.ecg() << gv.ecb() << "} shading constant}{ " << "SPHERE\n" << std::sqrt(CGAL::to_double(S.squared_radius())) << "\n"; bool raw_bak = gv.set_raw(true); gv << Point_3(S.center()) << "}})"; gv.set_raw(raw_bak); gv.set_ascii_mode(ascii_bak); return gv; } #endif #if defined CGAL_RAY_2_H && \ !defined CGAL_GV_OUT_RAY_2_H #define CGAL_GV_OUT_RAY_2_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Ray_2 &r) { // Note: it won't work if double is not convertible to an RT... const Bbox_3 & bb = gv.get_bbox(); Object result = intersection(Iso_rectangle_2( Point_2(bb.xmin(), bb.ymin()), Point_2(bb.xmax(), bb.ymax())), r); Point_2 ipoint; Segment_2 iseg; if (assign(ipoint, result)) gv << ipoint; else if (assign(iseg, result)) gv << iseg; return gv; } #endif #if defined CGAL_LINE_2_H && \ !defined CGAL_GV_OUT_LINE_2_H #define CGAL_GV_OUT_LINE_2_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Line_2 &r) { // Note: it won't work if double is not convertible to an RT... const Bbox_3 & bb = gv.get_bbox(); Object result = intersection(Iso_rectangle_2( Point_2(bb.xmin(), bb.ymin()), Point_2(bb.xmax(), bb.ymax())), r); Point_2 ipoint; Segment_2 iseg; if (assign(ipoint, result)) gv << ipoint; else if (assign(iseg, result)) gv << iseg; return gv; } #endif // Ray and Line drawing should be done by intersecting them with the BBox // of the Geomview_stream. But for now we take the easy approach. #if defined CGAL_RAY_3_H && \ !defined CGAL_GV_OUT_RAY_3_H #define CGAL_GV_OUT_RAY_3_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Ray_3 &r) { typename R::Segment_3 s(r.source(), r.point(1)); gv << s; return gv; } #endif #if defined CGAL_LINE_3_H && \ !defined CGAL_GV_OUT_LINE_3_H #define CGAL_GV_OUT_LINE_3_H template < class R > Geomview_stream& operator<<(Geomview_stream &gv, const Line_3 &r) { typename R::Segment_3 s(r.point(-1), r.point(1)); gv << s; return gv; } #endif CGAL_EXPORT Geomview_stream& operator<<(Geomview_stream &gv, const Bbox_2 &bbox); CGAL_EXPORT Geomview_stream& operator<<(Geomview_stream &gv, const Bbox_3 &bbox); #if defined CGAL_POINT_3_H && !defined CGAL_GV_IN_POINT_3_H #define CGAL_GV_IN_POINT_3_H template < class R > Geomview_stream& operator>>(Geomview_stream &gv, Point_3 &point) { const char *gclpick = "(pick world pickplane * nil nil nil nil nil nil nil)"; bool ascii_bak = gv.set_ascii_mode(); gv << "(pickable pickplane yes) (ui-target pickplane yes)" << "(interest " << gclpick << ")"; char sexpr[1024]; gv >> sexpr; // this reads a gcl expression const char* pickpoint = Geomview_stream::nth(sexpr, 3); // this gives something as: (0.0607123 0.0607125 4.76837e-07 0.529628) double x, y, z, w; Geomview_stream::parse_point(pickpoint, x, y, z, w); point = Point_3(x, y, z, w); // we echo the input if (gv.get_echo()) gv << point; // we are done and tell geomview to stop sending pick events gv << "(uninterest " << gclpick << ") (pickable pickplane no)"; gv.set_ascii_mode(ascii_bak); return gv; } #endif } //namespace CGAL #ifdef CGAL_HEADER_ONLY #include #endif // CGAL_HEADER_ONLY #endif // CGAL_USE_GEOMVIEW #endif // CGAL_GEOMVIEW_STREAM_H