// Copyright (c) 2006,2007,2008,2009,2010,2011 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 // 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: GPL-3.0+ // // Author(s) : Ron Wein #ifndef CGAL_FIG_STREAM_H #define CGAL_FIG_STREAM_H #include #include #include #include #include #include namespace CGAL { /*! * FIG colors. */ enum Fig_color { // Predefined colors: FIG_BLACK = 0, FIG_BLUE = 1, FIG_GREEN = 2, FIG_CYAN = 3, FIG_RED = 4, FIG_MAGENTA = 5, FIG_YELLOW = 6, FIG_WHITE = 7, FIG_BLUE_1 = 8, FIG_BLUE_2 = 9, FIG_BLUE_3 = 10, FIG_BLUE_4 = 11, FIG_GREEN_1 = 12, FIG_GREEN_2 = 13, FIG_GREEN_3 = 14, FIG_CYAN_1 = 15, FIG_CYAN_2 = 16, FIG_CYAN_3 = 17, FIG_RED_1 = 18, FIG_RED_2 = 19, FIG_RED_3 = 20, FIG_MAGENTA_1 = 21, FIG_MAGENTA_2 = 22, FIG_MAGENTA_3 = 23, FIG_BROWN_1 = 24, FIG_BROWN_2 = 25, FIG_BROWN_3 = 26, FIG_PINK_1 = 27, FIG_PINK_2 = 28, FIG_PINK_3 = 29, FIG_PINK_4 = 30, FIG_GOLD = 31, // User-defined colors: FIG_FIRST_USER_DEFINED_COLOR = 32, FIG_LAST_USER_DEFINED_COLOR = 543 }; /*! * FIG line styles. */ enum Fig_line_style { FIG_SOLID = 0, FIG_DASHED = 1, FIG_DOTTED = 2, FIG_DASH_DOTTED = 3, FIG_DASH_DOUBLE_DOTTED = 4, FIG_DASH_TRIPLE_DOTTED = 5 }; #define FIG_DEFAULT_STYLE_VALUE 4.0 /*! * FIG fill styles. */ enum Fig_fill_style { FIG_NOT_FILLED = -1, FIG_FILL_BLACK = 0, /// Values from 1 to 19 are shades of the color from darker to lighter. FIG_FILLED = 20, /// Values from 21 to 39 are tints of the color from the color to white. FIG_FILL_WHITE = 40, FIG_LEFT_DIAG_30DEG = 41, FIG_RIGHT_DIAG_30DEG = 42, FIG_CROSS_DIAG_30DEG = 43, FIG_LEFT_DIAG_45DEG = 44, FIG_RIGHT_DIAG_45DEG = 45, FIG_CROSS_DIAG_45DEG = 46, FIG_HORIZONTAL_BRICKS = 47, FIG_VERTICAL_BRICKS = 48, FIG_HORIZONTAL_LINES = 49, FIG_VERTICAL_LINES = 50, FIG_CROSS_LINES = 51, FIG_HORIZONTAL_RIGHT_SHINGLES = 52, FIG_HORIZONTAL_LEFT_SHINGLES = 53, FIG_VERTICAL_RIGHT_SHINGLES = 54, FIG_VERTICAL_LEFT_SHINGLES = 55, FIG_FISH_SCALES = 56, FIG_SMALL_FISH_SCALES = 57, FIG_CIRCLES = 58, FIG_HEXAGONS = 59, FIG_OCTAGONS = 60, FIG_HORIZONTAL_TIRE_TREADS = 61, FIG_VERTICAL_TIRE_TREADS = 62 }; /*! * FIG arrow types. */ enum Fig_arrow_type { FIG_STICK = 0, FIG_TRIANGLE = 1, FIG_INDENTED_BUTT = 2, FIG_POINTED_BUTT = 3 }; /*! * Arrow modes (not based on the FIG format). */ enum Fig_arrow_mode { FIG_NO_ARROW, FIG_FORWARD_ARROW, FIG_BACKWARD_ARROW, FIG_BOTH_ARROWS }; /*! * Point styles (not based on the FIG format). */ enum Fig_point_style { FIG_CROSS, FIG_PLUS, FIG_CIRCLE, FIG_DISC, FIG_SQUARE, FIG_BOX, FIG_RHOMBUS, FIG_DIAMOND }; /*! * FIG fonts. */ enum Fig_font { FIG_ROMAN = 1, FIG_BOLD = 2, FIG_ITALIC = 3, FIG_SANS_SERIF = 4, FIG_TYPEWRITER = 5 }; /*! * Depth constants. */ enum Fig_depth { FIG_MIN_DEPTH = 0, FIG_DEFAULT_DEPTH = 50, FIG_MAX_DEPTH = 99 }; /*! * \class A class for writing geometric objects in a FIG format (version 3.2). * For more details, see: http://www.xfig.org/userman/fig-format.html */ template class Fig_stream { public: typedef Kernel_ Kernel; // Define the kernel objects. typedef typename Kernel::FT NT; typedef typename Kernel::Point_2 Point_2; typedef typename Kernel::Segment_2 Segment_2; typedef typename Kernel::Ray_2 Ray_2; typedef typename Kernel::Line_2 Line_2; typedef typename Kernel::Triangle_2 Triangle_2; typedef typename Kernel::Iso_rectangle_2 Iso_rectangle_2; typedef Polygon_2 Polygon_2; typedef typename Kernel::Circle_2 Circle_2; protected: // Data members: std::ofstream _ofile; // The output file. Iso_rectangle_2 _bound_rect; // A rectangle bounding the workspace. int _width; // Figure width (in pixels). int _height; // Figure height (in pixels). double _scale; // Scaling factor. int _depth; Fig_color _color; int _line_width; Fig_line_style _line_style; double _style_value; Fig_color _fill_color; Fig_fill_style _fill_style; Fig_point_style _point_style; NT _point_size; Fig_arrow_mode _arrow_mode; Fig_arrow_type _arrow_type; NT _arrow_width; NT _arrow_height; Fig_font _font; int _font_size; bool colors[FIG_LAST_USER_DEFINED_COLOR + 1]; // Kernel functors. typename Kernel::Intersect_2 intersect_func; private: // Copy constructor and assignment operator - not supported. Fig_stream (const Fig_stream& ); const Fig_stream& operator= (const Fig_stream& ); public: /// \name Constructors and destructor. //@{ /*! * Default constructor. */ Fig_stream () : _width (0), _height (0), _scale (0), _depth (FIG_DEFAULT_DEPTH), _color (FIG_BLACK), _line_width (1), _line_style (FIG_SOLID), _style_value (FIG_DEFAULT_STYLE_VALUE), _fill_color (FIG_WHITE), _fill_style (FIG_NOT_FILLED), _point_style (FIG_DISC), _arrow_mode (FIG_NO_ARROW), _arrow_type (FIG_STICK), _font (FIG_ROMAN), _font_size (12) { // Reset all colors. _reset_colors (); // Construct the necessary kernel functors. Kernel ker; intersect_func = ker.intersect_2_object(); } /*! * Constructor. * \param filename The name of the output FIG file. * \param rect A rectangle bounding the logical drawing area. * \param width The physical width of the figure (in FIG units). * \param height The physical height of the figure (in FIG units). * \pre The bounding rectangle is valid and the physical dimensions are * both positive. */ Fig_stream (const char *filename, const Iso_rectangle_2& rect, const int& width = 12000, const int& height = 12000) : _width (0), _height (0), _scale (0), _depth (FIG_DEFAULT_DEPTH), _color (FIG_BLACK), _line_width (1), _line_style (FIG_SOLID), _style_value (FIG_DEFAULT_STYLE_VALUE), _fill_color (FIG_WHITE), _fill_style (FIG_NOT_FILLED), _point_style (FIG_DISC), _arrow_mode (FIG_NO_ARROW), _arrow_type (FIG_STICK), _font (FIG_ROMAN), _font_size (12) { // Reset all colors. _reset_colors (); // Construct the necessary kernel functors. Kernel ker; intersect_func = ker.intersect_2_object(); // Open the file. open (filename, rect, width, height); } /*! * Destructor. */ virtual ~Fig_stream () { _ofile.close(); } //@} /// \name Openning and closing the file. //@{ /*! * Check whether the file is open. */ bool is_open () { return (_ofile.is_open()); } /*! * Open a FIG file. * \param filename The name of the output FIG file. * \param rect A rectangle bounding the logical drawing area. * \param width The physical width of the figure (in FIG units). * \param height The physical height of the figure (in FIG units). * \pre The bounding rectangle is valid and the physical dimensions are * both positive. * \return Whether the file was successfully opened. */ bool open (const char *filename, const Iso_rectangle_2& rect, const int& width = 12000, const int& height = 12000) { CGAL_precondition (width > 0); CGAL_precondition (height > 0); CGAL_precondition (rect.xmax() > rect.xmin()); CGAL_precondition (rect.ymax() > rect.ymin()); // Reset all colors. _reset_colors (); // Close the current output file, if necessary. if (_ofile.is_open()) _ofile.close(); // Open the output file. _ofile.open (filename); // Set the logical and physical dimensions. _bound_rect = rect; _width = width; _height = height; // Compute the scale. const double x_scale = width / CGAL::to_double(rect.xmax() - rect.xmin()); const double y_scale = height / CGAL::to_double(rect.ymax() - rect.ymin()); _scale = (x_scale < y_scale) ? x_scale : y_scale; // Set the default point size and arrow dimensions. _point_size = (rect.xmax() - rect.xmin()) / NT(500); _arrow_width = _point_size; _arrow_height = 2*_point_size; // End here if the file is not opened. if (! _ofile.is_open()) return (false); // Write the FIG header. _ofile << "#FIG 3.2" << std::endl; _ofile << "Landscape" << std::endl; _ofile << "Center" << std::endl; _ofile << "Inches" << std::endl; _ofile << "Letter" << std::endl; _ofile << "100.00" << std::endl; _ofile << "Single" << std::endl; _ofile << "-2" << std::endl; _ofile << "1200 2" << std::endl; return (true); } /*! * Close the FIG file. */ void close () { if (_ofile.is_open()) _ofile.close(); // Reset all colors. _reset_colors (); } //@} /// \name Accessing drawing properties. //@{ /*! * Get the workspace bounding rectangle. */ Iso_rectangle_2 bounding_rect() const { return (_bound_rect); } /* /\*! */ /* * Set the workspace bounding rectangle. */ /* *\/ */ /* void set_bounding_rect(const Iso_rectangle_2& rect) */ /* { */ /* _bound_rect = rect; */ /* } */ /*! * Get the physical width of the fig */ int width () const { return _width; } /*! * Get the physical height of the fig */ int height () const { return _height; } /*! * Get the depth. */ int depth () const { return (depth); } /*! * Get the color. */ Fig_color color () const { return (_color); } /*! * Get the line width. */ int line_width () const { return (line_width); } /*! * Get the line style. */ Fig_line_style line_style () const { return (_line_style); } /*! * Get the style value. */ double style_value () const { return (_style_value); } /*! * Get the fill color. */ Fig_color fill_color () const { return (_fill_color); } /*! * Get the fill style. */ Fig_fill_style fill_style () const { return (_fill_style); } /*! * Get the point style. */ Fig_point_style point_style () const { return (_point_style); } /*! * Get the point size. */ const NT& point_size () const { return (_point_size); } /*! * Get the arrow drawing mode (this mode is relevent when drawing segments, * polylines, circular arcs or splines). */ Fig_arrow_mode arrow_mode () const { return (_arrow_mode); } /*! * Get the arrow type. */ Fig_arrow_type arrow_type () const { return (_arrow_type); } /*! * Get the arrow width. */ const NT& arrow_width () const { return (_arrow_width); } /*! * Get the arrow height. */ const NT& arrow_height () const { return (_arrow_height); } /*! * Get the font. */ Fig_font font () const { return (_font); } /*! * Get the font size. */ int font_size () const { return (_font_size); } //@} /// \name Set the drawing properties. //@{ /*! * Set the depth. */ void set_depth (const int& depth) { if (depth < static_cast(FIG_MIN_DEPTH)) _depth = static_cast(FIG_MIN_DEPTH); else if (depth > static_cast(FIG_MAX_DEPTH)) _depth = static_cast(FIG_MAX_DEPTH); else _depth = depth; return; } /*! * Set the color. * \pre The color must be defined. */ void set_color (const Fig_color& color) { CGAL_precondition (color_defined (color)); if (color_defined (color)) _color = color; return; } /*! * Set the line width. */ void set_line_width (const unsigned int& width) { _line_width = static_cast(width); return; } /*! * Set the line style. */ void set_line_style (const Fig_line_style& style) { _line_style = style; return; } /*! * Set the style value. */ void set_style_value (const double& val) { CGAL_precondition (val > 0); _style_value = val; return; } /*! * Set the fill color. * \pre The color must be defined. */ void set_fill_color (const Fig_color& color) { CGAL_precondition (color_defined (color)); if (color_defined (color)) _fill_color = color; return; } /*! * Set the fill style. */ void set_fill_style (const Fig_fill_style& style) { _fill_style = style; return; } /*! * Set the point style. */ void set_point_style (const Fig_point_style& style) { _point_style = style; return; } /*! * Set the point size. */ void set_point_size (const NT& size) { _point_size = CGAL::abs(size); return; } /*! * Set the arrow drawing mode. This mode will be applied when drawing * segments, polylines, circular arcs or splines. */ void set_arrow_mode (const Fig_arrow_mode& mode) { _arrow_mode = mode; return; } /*! * Set the arrow type. */ void set_arrow_type (const Fig_arrow_type& type) { _arrow_type = type; return; } /*! * Set the arrow width. */ void set_arrow_width (const NT& width) { _arrow_width = CGAL::abs(width); return; } /*! * Get the arrow height. */ void set_arrow_height (const NT& height) { _arrow_height = CGAL::abs(height); return; } /*! * Set the font. */ void set_font (const Fig_font& font) { _font = font; return; } /*! * Set the font size. */ void set_font_size (const unsigned int& size) { _font_size = static_cast(size); return; } //@} /// \name Defining colors. //@{ /*! * Check if a color is defined. */ bool color_defined (const Fig_color& color) const { int col = static_cast(color); if (col < 0 || col > FIG_LAST_USER_DEFINED_COLOR) return (false); return (colors[col]); } /*! * Add a user-defined color. * Use this function after openning the FIG stream and before writing any * other object (i.e. before calling the write_ () functions). * \param color The color. * \param r The red component (0 - 255). * \param g The green component (0 - 255). * \param b The blue component (0 - 255). * \pre The color must be undefined. */ void define_color (const Fig_color& color, const unsigned char& r, const unsigned char& g, const unsigned char& b) { CGAL_precondition (color_defined (color)); CGAL_precondition (_ofile.is_open()); if (color_defined (color)) return; // Prepare a string desribing the color. char color_desc [10]; sprintf ("#%02x%02x%02x", r, g, b); // Write the color to the FIG file. _ofile << "0 " // Desginates a color pseudo-object. << static_cast(color) << ' ' << color_desc << std::endl; // Mark that the color is now defined. colors[static_cast(color)] = true; return; } //@} /// \name Writing objects. //@{ /*! * Write a point. */ void write_point (const Point_2& p) { CGAL_precondition (_ofile.is_open()); //is the point outside the iso-rectangle? if(_bound_rect.has_on_unbounded_side(p)) return; switch (_point_style) { case (FIG_CROSS): case (FIG_PLUS): { // Draw two segments intersecting at p. Point_2 s1, t1; Point_2 s2, t2; if (_point_style == FIG_PLUS) { // Draw a '+'. s1 = Point_2 (p.x() - _point_size, p.y()); t1 = Point_2 (p.x() + _point_size, p.y()); s2 = Point_2 (p.x(), p.y() - _point_size); t2 = Point_2 (p.x(), p.y() + _point_size); } else { // Draw an 'x'. s1 = Point_2 (p.x() - _point_size, p.y() - _point_size); t1 = Point_2 (p.x() + _point_size, p.y() + _point_size); s2 = Point_2 (p.x() - _point_size, p.y() + _point_size); t2 = Point_2 (p.x() + _point_size, p.y() - _point_size); } // Draw solid lines with width 1. _write_segment (Segment_2(s1, t1), _color, 1, FIG_SOLID, _style_value, false); _write_segment (Segment_2(s2, t2), _color, 1, FIG_SOLID, _style_value, false); break; } case (FIG_CIRCLE): { // Draw an empty circle (use a solid line with width 1). _write_ellipse (p, CGAL::square(_point_size), CGAL::square(_point_size), _color, 1, FIG_SOLID, _style_value, FIG_WHITE, FIG_NOT_FILLED); break; } case (FIG_DISC): { // Draw a filled disc. _write_ellipse (p, CGAL::square(_point_size), CGAL::square(_point_size), _color, 1, FIG_SOLID, _style_value, _color, FIG_FILLED); break; } case (FIG_SQUARE): case (FIG_BOX): case (FIG_RHOMBUS): case (FIG_DIAMOND): { // Prepare the rectangle vertices. std::vector vertices (4); if (_point_style == FIG_SQUARE || _point_style == FIG_BOX) { vertices[0] = Point_2 (p.x() - _point_size, p.y() - _point_size); vertices[1] = Point_2 (p.x() - _point_size, p.y() + _point_size); vertices[2] = Point_2 (p.x() + _point_size, p.y() + _point_size); vertices[3] = Point_2 (p.x() + _point_size, p.y() - _point_size); } else { vertices[0] = Point_2 (p.x(), p.y() - _point_size); vertices[1] = Point_2 (p.x() + _point_size, p.y()); vertices[2] = Point_2 (p.x(), p.y() + _point_size); vertices[3] = Point_2 (p.x() - _point_size, p.y()); } if (_point_style == FIG_SQUARE || _point_style == FIG_RHOMBUS) { // Draw an empty rectangular shape (use a solid line with width 1). _write_polygon (4, vertices.begin(), vertices.end(), _color, 1, FIG_SOLID, _style_value, FIG_WHITE, FIG_NOT_FILLED); } else { // Draw a filled rectangular shape. _write_polygon (4, vertices.begin(), vertices.end(), _color, 1, FIG_SOLID, _style_value, _color, FIG_FILLED); } break; } } return; } /*! * Write a segment. */ void write_segment (const Segment_2& seg) { CGAL_precondition (_ofile.is_open()); // Clip the ray using the bounding rectangle. CGAL::Object obj = intersect_func (_bound_rect, seg); Segment_2 clipped_seg; // Draw only the clipped segment (draw nothing if the segment does not // intersect the bounding rectangle). if (CGAL::assign (clipped_seg, obj)) { _write_segment (clipped_seg, _color, _line_width, _line_style, _style_value, false); } return; } /*! * Write a ray. */ void write_ray (const Ray_2& ray) { CGAL_precondition (_ofile.is_open()); // Clip the ray using the bounding rectangle. CGAL::Object obj = intersect_func (_bound_rect, ray); Segment_2 seg; // Draw only the clipped segment (draw nothing if the ray does not // intersect the bounding rectangle). if (CGAL::assign (seg, obj)) { _write_segment (seg, _color, _line_width, _line_style, _style_value, false); } return; } /*! * Write a line. */ void write_line (const Line_2& line) { CGAL_precondition (_ofile.is_open()); // Clip the ray using the bounding rectangle. CGAL::Object obj = intersect_func (_bound_rect, line); Segment_2 seg; // Draw only the clipped segment (draw nothing if the ray does not // intersect the bounding rectangle). if (CGAL::assign (seg, obj)) { _write_segment (seg, _color, _line_width, _line_style, _style_value, false); } return; } /*! * Write a triangle. */ void write_triangle (const Triangle_2& tri) { CGAL_precondition (_ofile.is_open()); std::vector vertices(3); vertices[0] = tri.vertex(0); vertices[1] = tri.vertex(1); vertices[2] = tri.vertex(2); _write_polygon (3, vertices.begin(), vertices.end(), _color, _line_width, _line_style, _style_value, _fill_color, _fill_style); return; } /*! * Write an iso-rectangle. */ void write_rectangle (const Iso_rectangle_2& rect) { CGAL_precondition (_ofile.is_open()); std::vector vertices(4); vertices[0] = rect.vertex(0); vertices[1] = rect.vertex(1); vertices[2] = rect.vertex(2); vertices[3] = rect.vertex(3); _write_polygon (4, vertices.begin(), vertices.end(), _color, _line_width, _line_style, _style_value, _fill_color, _fill_style); return; } /*! * Write a polyline. * \param begin An iterator of the control points (of type Point_2). * \param end A past-the-end iterator for the control points. */ template void write_polyline (const Input_iterator& begin, const Input_iterator& end) { CGAL_precondition (_ofile.is_open()); _write_polyline (begin, end, _color, _line_width, _line_style, _style_value, false); return; } /*! * Write a polygon. */ void write_polygon (const Polygon_2& pgn) { CGAL_precondition (_ofile.is_open()); _write_polygon (pgn.size(), pgn.vertices_begin(), pgn.vertices_end(), _color, _line_width, _line_style, _style_value, _fill_color, _fill_style); return; } /*! * Write a circle. */ void write_circle (const Circle_2& circ) { CGAL_precondition (_ofile.is_open()); _write_ellipse (circ.center(), circ.squared_radius(), circ.squared_radius(), _color, _line_width, _line_style, _style_value, _fill_color, _fill_style); return; } /*! * Write a canonical ellipse. * \param center The center of the ellipse (the intersection of its axes). * \param r1_squared The squared length of the axis parallel to the x-axis. * \param r2_squared The squared length of the axis parallel to the y-axis. */ void write_ellipse (const Point_2& center, const NT& r1_squared, const NT& r2_squared) { CGAL_precondition (_ofile.is_open()); _write_ellipse (center, r1_squared, r2_squared, _color, _line_width, _line_style, _style_value, _fill_color, _fill_style); return; } /*! * Write a circular arc. * \param p1 The source point of the arc. * \param p2 A midpoint on the arc. * \param p3 The target point of the arc. * \pre The three points are not collinear. */ void write_circular_arc (const Point_2& p1, const Point_2& p2, const Point_2& p3) { CGAL_precondition (_ofile.is_open()); _write_arc (p1, p2, p3, _color, _line_width, _line_style, _style_value); return; } /*! * Write a spline. * \param begin An iterator of the control points (of type Point_2). * \param end A past-the-end iterator for the control points. * \param factor A shape factor for the spline: A value in the range [-1,1], * where negative values are used for interpolated splines * and positive values for approximated splines. * The default value if 1. */ template void write_spline (const Input_iterator& begin, const Input_iterator& end, const float& factor = 1) { CGAL_precondition (_ofile.is_open()); if (begin == end) return; // Normalize the shape factor. float shape_factor; if (factor > 1) shape_factor = 1; else if (factor < -1) shape_factor = -1; else shape_factor = factor; _write_spline (begin, end, shape_factor, _color, _line_width, _line_style, _style_value); } /*! * Write a text box. * \param pos The lower-left corner of the text box. * \param text The text to write. * \param angle The angle (in radians) that the text forms with the x-axis * (0 by default). */ void write_text (const Point_2& pos, const char *text, const double& angle = 0) { CGAL_precondition (_ofile.is_open()); if (text == NULL || strlen(text) == 0) return; _write_text (pos, reinterpret_cast(text), strlen(text), angle, _color, _font, _font_size); return; } //@} /// \name Setting the draw properties via the << operator. //@{ /*! * Set the depth. */ Fig_stream& operator<< (const Fig_depth& depth) { set_depth (static_cast(depth)); return (*this); } /*! * Set the color. */ Fig_stream& operator<< (const Fig_color& color) { set_color (color); return (*this); } /*! * Set the line style. */ Fig_stream& operator<< (const Fig_line_style& style) { set_line_style (style); return (*this); } /*! * Set the fill style. */ Fig_stream& operator<< (const Fig_fill_style& style) { set_fill_style (style); return (*this); } /*! * Set the point style. */ Fig_stream& operator<< (const Fig_point_style& style) { set_point_style (style); return (*this); } /*! * Set the arrow drawing mode. This mode will be applied when drawing * segments, polylines, circular arcs or splines. */ Fig_stream& operator<< (const Fig_arrow_mode& mode) { set_arrow_mode (mode); return (*this); } /*! * Set the arrow type. */ Fig_stream& operator<< (const Fig_arrow_type& type) { set_arrow_type (type); return (*this); } /*! * Set the font. */ Fig_stream& operator<< (const Fig_font& font) { set_font (font); return (*this); } //@} /// \name Drawing objects via the << operator. //@{ /*! * Write a point. */ Fig_stream& operator<< (const Point_2& p) { write_point (p); return (*this); } /*! * Write a line segment. */ Fig_stream& operator<< (const Segment_2& seg) { write_segment (seg); return (*this); } /*! * Write a ray. */ Fig_stream& operator<< (const Ray_2& ray) { write_ray (ray); return (*this); } /*! * Write a line. */ Fig_stream& operator<< (const Line_2& line) { write_line (line); return (*this); } /*! * Write a triangle. */ Fig_stream& operator<< (const Triangle_2& tri) { write_triangle (tri); return (*this); } /*! * Write a rectangle. */ Fig_stream& operator<< (const Iso_rectangle_2& rect) { write_rectangle (rect); return (*this); } /*! * Write a polygon. */ Fig_stream& operator<< (const Polygon_2& pgn) { write_polygon (pgn); return (*this); } /*! * Write a circle. */ Fig_stream& operator<< (const Circle_2& circ) { write_circle (circ); return (*this); } //@} protected: /*! * Convert a point to FIG units. */ void _convert_point (const Point_2& p, int& ix, int& iy) const { ix = static_cast (_scale * CGAL::to_double(p.x() - _bound_rect.xmin())); iy = static_cast (_scale * CGAL::to_double( _bound_rect.ymax() - p.y())); return; } /*! * Write a segment. */ void _write_segment (const Segment_2& seg, const Fig_color& line_color, const int& line_width, const Fig_line_style& line_style, const double& style_value, const bool& draw_arrows) { // Convert the segment to a polyline with two points and write it. std::vector points (2); points[0] = seg.source(); points[1] = seg.target(); _write_polyline (points.begin(), points.end(), line_color, line_width, line_style, style_value, draw_arrows); return; } /*! * Write a polyline. */ template void _write_polyline (Input_iterator begin, Input_iterator end, const Fig_color& line_color, const int& line_width, const Fig_line_style& line_style, const double& style_value, const bool& draw_arrows) { // Check if we should draw arrows. bool forward_arrow = false; bool backward_arrow = false; if (draw_arrows) { forward_arrow = (_arrow_mode == FIG_FORWARD_ARROW) || (_arrow_mode == FIG_BOTH_ARROWS); backward_arrow = (_arrow_mode == FIG_BACKWARD_ARROW) || (_arrow_mode == FIG_BOTH_ARROWS); } // Count the number of points in the spline. int n_points = std::distance (begin, end); // Write the segment properties. _ofile << "2 1 " // Desginate a polyline. << line_style << ' ' << line_width << ' ' << line_color << ' ' << FIG_WHITE << ' ' // Fill color (dummy). << _depth << ' ' << "0 " // Pen style (not in use, always 0). << FIG_NOT_FILLED << ' ' << style_value << ' ' << "0 " // Join style (always 0). << "0 " // Cap style (always 0). << "-1 " // Radius (not in use for lines). << forward_arrow << ' ' << backward_arrow << ' ' << n_points << std::endl; // Write the points defining the polyline. bool is_first = true; int ix, iy; while (begin != end) { if (is_first) { _ofile << '\t'; is_first = false; } else { _ofile << ' '; } _convert_point (*begin, ix, iy); _ofile << ix << ' ' << iy; begin++; } _ofile << std::endl; // Write the arrows, if necessary. if (forward_arrow) _write_arrow_line (); if (backward_arrow) _write_arrow_line (); return; } /*! * Write a polygon, reprsented as a range of points. */ template void _write_polygon (const int n_points, Input_iterator begin, Input_iterator end, const Fig_color& line_color, const int line_width, const Fig_line_style& line_style, const double& style_value, const Fig_color& fill_color, const Fig_fill_style& fill_style) { // Write the polyline properties. _ofile << "2 3 " // Desginate a polygon. << line_style << ' ' << line_width << ' ' << line_color << ' ' << fill_color << ' ' << _depth << ' ' << "0 " // Pen style (not in use, always 0). << fill_style << ' ' << style_value << ' ' << "0 " // Join style (always 0). << "0 " // Cap style (always 0). << "-1 " // Radius (not in use for lines). << "0 " // No forward arrow. << "0 " // No backward arrow. << n_points + 1 << std::endl; // Write the points. bool is_first = true; Point_2 first = *begin; int ix, iy; while (begin != end) { if (is_first) { _ofile << '\t'; is_first = false; } else { _ofile << ' '; } _convert_point (*begin, ix, iy); _ofile << ix << ' ' << iy; begin++; } // Write the first point again. _convert_point (first, ix, iy); _ofile << ' ' << ix << ' ' << iy << std::endl; return; } /*! * Write an ellipse. */ void _write_ellipse (const Point_2& center, const NT& squared_radius_x, const NT& squared_radius_y, const Fig_color& line_color, const int& line_width, const Fig_line_style& line_style, const double& style_value, const Fig_color& fill_color, const Fig_fill_style& fill_style) { // Write the ellipse properties. _ofile << "1 1 " // Desginate an ellipse. << line_style << ' ' << line_width << ' ' << line_color << ' ' << fill_color << ' ' << _depth << ' ' << "0 " // Pen style (not in use, always 0). << fill_style << ' ' << style_value << ' ' << "1 " // Direction (always 1). << "0.000 "; // Angle (in radians). // Write the center point. int ix, iy; _convert_point (center, ix, iy); _ofile << ' ' << ix << ' ' << iy; // Write the radii. int rx = static_cast (_scale * std::sqrt(CGAL::to_double(squared_radius_x))); int ry = static_cast (_scale * std::sqrt(CGAL::to_double(squared_radius_y))); _ofile << ' ' << rx << ' ' << ry; // Write the start point (the center) and the end point (one corner of // the rectangles bounding the ellipse). _ofile << ' ' << ix << ' ' << iy << ' ' << (ix + rx) << ' ' << (iy +ry) << std::endl; return; } /*! * Write an arc. */ void _write_arc (const Point_2& p1, const Point_2& p2, const Point_2& p3, const Fig_color& line_color, const int& line_width, const Fig_line_style& line_style, const double& style_value) { // Check if we should draw arrows. bool forward_arrow; bool backward_arrow; forward_arrow = (_arrow_mode == FIG_FORWARD_ARROW) || (_arrow_mode == FIG_BOTH_ARROWS); backward_arrow = (_arrow_mode == FIG_BACKWARD_ARROW) || (_arrow_mode == FIG_BOTH_ARROWS); // Construct the supporting circle of the arc and use its center and // orientation. Circle_2 circ (p1, p2, p3); int orient = (circ.orientation() == CGAL::CLOCKWISE) ? 0 : 1; // Write the arc properties. _ofile << "5 1 " // Desginate an open arc. << line_style << ' ' << line_width << ' ' << line_color << ' ' << FIG_WHITE << ' ' // Fill color (dummy). << _depth << ' ' << "0 " // Pen style (not in use, always 0). << FIG_NOT_FILLED << ' ' << style_value << ' ' << "0 " // Cap style (always 0). << orient << ' ' << forward_arrow << ' ' << backward_arrow << ' '; // Write the center of the circle. int ix, iy; _convert_point (circ.center(), ix, iy); _ofile << ix << ' ' << iy; // Write the three points defining the arc. _convert_point (p1, ix, iy); _ofile << ' ' << ix << ' ' << iy; _convert_point (p2, ix, iy); _ofile << ' ' << ix << ' ' << iy; _convert_point (p3, ix, iy); _ofile << ' ' << ix << ' ' << iy << std::endl; // Write the arrows, if necessary. if (forward_arrow) _write_arrow_line (); if (backward_arrow) _write_arrow_line (); return; } /*! * Write a spline */ template void _write_spline (Input_iterator begin, Input_iterator end, const float& factor, const Fig_color& line_color, const int& line_width, const Fig_line_style& line_style, const double& style_value) { // Check if we should draw arrows. bool forward_arrow; bool backward_arrow; forward_arrow = (_arrow_mode == FIG_FORWARD_ARROW) || (_arrow_mode == FIG_BOTH_ARROWS); backward_arrow = (_arrow_mode == FIG_BACKWARD_ARROW) || (_arrow_mode == FIG_BOTH_ARROWS); // Count the number of points in the spline. int n_points = std::distance (begin, end); // Write the spline properties. _ofile << "3 0 " // Desginate an open spline. << line_style << ' ' << line_width << ' ' << line_color << ' ' << FIG_WHITE << ' ' // Fill color (dummy). << _depth << ' ' << "0 " // Pen style (not in use, always 0). << FIG_NOT_FILLED << ' ' << style_value << ' ' << "0 " // Cap style (always 0). << forward_arrow << ' ' << backward_arrow << ' ' << n_points << std::endl; // Write the points defining the spline. bool is_first = true; int ix, iy; while (begin != end) { if (is_first) { _ofile << '\t'; is_first = false; } else { _ofile << ' '; } _convert_point (*begin, ix, iy); _ofile << ix << ' ' << iy; begin++; } _ofile << std::endl; // Write the shape factors: 0 for the endpoints and (factor) for each // of the midpoints. int i; _ofile << '\t' << "0.000"; for (i = 0; i < n_points - 2; i++) _ofile << ' ' << factor; _ofile << '\t' << "0.000" << std::endl; // Write the arrows, if necessary. if (forward_arrow) _write_arrow_line (); if (backward_arrow) _write_arrow_line (); return; } /*! * Write an arrow line. */ void _write_arrow_line () { int width = static_cast (_scale * CGAL::to_double(_arrow_width)); int height = static_cast (_scale * CGAL::to_double(_arrow_height)); _ofile << _arrow_type << ' ' << "0 " // Arrow style (always 0). << _line_width << ' ' << width << ' ' << height << std::endl; return; } /*! * Write a text box. */ void _write_text (const Point_2& pos, const unsigned char *text, const int& len_text, const double& angle, const Fig_color& font_color, const Fig_font& font, const int& font_size) { // Compute the text-box dimensions. const int text_height = font_size * 1200 / 80; const int text_width = len_text * font_size * 1200 / 160; // Write the text properties. _ofile << "4 0 " // Desginate left-justified text. << font_color << ' ' << _depth << ' ' << "0 " // Pen style (not in use, always 0). << font << ' ' << font_size << ' ' << angle << ' ' << "2 " // Indicates a special LaTeX font. << text_height << ' ' << text_width; // Write the position coordinates. int ix, iy; _convert_point (pos, ix, iy); _ofile << ' ' << ix << ' ' << iy << ' '; // Write the text. char oct[10]; int i; for (i = 0; i < len_text; i++) { if (text[i] >= ' ' && text[i] < 128 && text[i] != '\\') { // If the current character is printable, just write it. _ofile << static_cast(text[i]); } else { // Convert the current character to an octal string and write it. sprintf (oct, "\\%03o", text[i]); _ofile << oct; } } // Write the end-of-string sequence. _ofile << "\\001" << std::endl; return; } /*! * Reset all user-defined colors. */ void _reset_colors () { int i; for (i = 0; i < FIG_FIRST_USER_DEFINED_COLOR; i++) colors[i] = true; for (i = FIG_FIRST_USER_DEFINED_COLOR; i < FIG_LAST_USER_DEFINED_COLOR; i++) { colors[i] = false; } return; } }; } //namespace CGAL #endif