generic-rect.h revision 827bc501341bcc5c344c0422f13422bc368151b4
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * \brief Axis-aligned rectangle
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Michael Sloan <mgsloan@gmail.com>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Krzysztof KosiĆski <tweenk.pl@gmail.com>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Copyright 2007-2011 Authors
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * This library is free software; you can redistribute it and/or
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz * modify it either under the terms of the GNU Lesser General Public
5c45bb188ab729e501e48732842cb9de6a9813beAlex Valavanis * License version 2.1 as published by the Free Software Foundation
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * (the "LGPL") or, at your option, under the terms of the Mozilla
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Public License Version 1.1 (the "MPL"). If you do not alter this
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * notice, a recipient may use your version of this file under either
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * the MPL or the LGPL.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * You should have received a copy of the LGPL along with this library
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * in the file COPYING-LGPL-2.1; if not, output to the Free Software
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * You should have received a copy of the MPL along with this library
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * in the file COPYING-MPL-1.1
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * The contents of this file are subject to the Mozilla Public License
47badd0035ae8c9135c51444f3770b17ae504ddaAlex Valavanis * Version 1.1 (the "License"); you may not use this file except in
47badd0035ae8c9135c51444f3770b17ae504ddaAlex Valavanis * compliance with the License. You may obtain a copy of the License at
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * OF ANY KIND, either express or implied. See the LGPL or the MPL for
17238dd97c572210f1036dd8a7a8657e67bfa9c3Campbell Barton * the specific language governing rights and limitations.
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * Authors of original rect class:
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * Lauris Kaplinski <lauris@kaplinski.com>
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * Nathan Hurst <njh@mail.csse.monash.edu.au>
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * bulia byak <buliabyak@users.sf.net>
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * MenTaLguY <mental@rydia.net>
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * @brief Axis aligned, non-empty, generic rectangle.
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * @ingroup Primitives
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz : boost::additive< GenericRect<C>, typename CoordTraits<C>::PointType
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz , boost::orable< GenericRect<C>, typename CoordTraits<C>::OptRectType
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz typedef typename CoordTraits<C>::IntervalType CInterval;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz typedef typename CoordTraits<C>::PointType CPoint;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz typedef typename CoordTraits<C>::RectType CRect;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz typedef typename CoordTraits<C>::OptRectType OptCRect;
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz /// @name Create rectangles.
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz /** @brief Create a rectangle that contains only the point at (0,0). */
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz /** @brief Create a rectangle from X and Y intervals. */
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz GenericRect(CInterval const &a, CInterval const &b) {
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz /** @brief Create a rectangle from two points. */
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz f[X] = CInterval(a[X], b[X]);
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz f[Y] = CInterval(a[Y], b[Y]);
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz /** @brief Create rectangle from coordinates of two points. */
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz /** @brief Create a rectangle from a range of points.
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * The resulting rectangle will contain all ponts from the range.
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * The return type of iterators must be convertible to Point.
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * The range must not be empty. For possibly empty ranges, see OptRect.
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * @param start Beginning of the range
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * @param end End of the range
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * @return Rectangle that contains all points from [start, end). */
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz static GenericRect<C> from_range(InputIterator start, InputIterator end) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Create a rectangle from a C-style array of points it should contain. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz static GenericRect<C> from_array(CPoint const *c, unsigned n) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz GenericRect<C> result = GenericRect<C>::from_range(c, c+n);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Create rectangle from origin and dimensions. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz static GenericRect<C> from_xywh(C x, C y, C w, C h) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Create rectangle from origin and dimensions. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz static GenericRect<C> from_xywh(CPoint const &xy, CPoint const &wh) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /// @name Inspect dimensions.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz CInterval &operator[](unsigned i) { return f[i]; }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz CInterval const &operator[](unsigned i) const { return f[i]; }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz CPoint min() const { return CPoint(f[X].min(), f[Y].min()); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz CPoint max() const { return CPoint(f[X].max(), f[Y].max()); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Return the n-th corner of the rectangle.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * If the Y axis grows upwards, this returns corners in clockwise order
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz * starting from the lower left. If Y grows downwards, it returns the corners
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz * in counter-clockwise order starting from the upper left. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz switch(i % 4) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz //We should probably remove these - they're coord sys gnostic
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Return top coordinate of the rectangle (+Y is downwards). */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Return bottom coordinate of the rectangle (+Y is downwards). */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Return leftmost coordinate of the rectangle (+X is to the right). */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Return rightmost coordinate of the rectangle (+X is to the right). */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Get the horizontal extent of the rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Get the vertical extent of the rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Get rectangle's width and height as a point.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * @return Point with X coordinate corresponding to the width and the Y coordinate
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * corresponding to the height of the rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz CPoint dimensions() const { return CPoint(f[X].extent(), f[Y].extent()); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Get the point in the geometric center of the rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz CPoint midpoint() const { return CPoint(f[X].middle(), f[Y].middle()); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Compute rectangle's area. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz C area() const { return f[X].extent() * f[Y].extent(); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Check whether the rectangle has zero area. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool hasZeroArea() const { return (area() == 0); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Get the larger extent (width or height) of the rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz C maxExtent() const { return std::max(f[X].extent(), f[Y].extent()); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Get the smaller extent (width or height) of the rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz C minExtent() const { return std::min(f[X].extent(), f[Y].extent()); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /// @name Test other rectangles and points for inclusion.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Check whether the rectangles have any common points. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool intersects(GenericRect<C> const &r) const {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz return f[X].intersects(r[X]) && f[Y].intersects(r[Y]);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Check whether the rectangle includes all points in the given rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz return f[X].contains(r[X]) && f[Y].contains(r[Y]);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Check whether the rectangles have any common points.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * A non-empty rectangle will not intersect empty rectangles. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz inline bool intersects(OptCRect const &r) const;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Check whether the rectangle includes all points in the given rectangle.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * A non-empty rectangle will contain any empty rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Check whether the given point is within the rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz return f[X].contains(p[X]) && f[Y].contains(p[Y]);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /// @name Modify the rectangle.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Set the upper left point of the rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Set the lower right point of the rectangle. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Enlarge the rectangle to contain the given point. */
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz /** @brief Enlarge the rectangle to contain the given rectangle. */
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz /** @brief Enlarge the rectangle to contain the given rectangle.
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz * Unioning with an empty rectangle results in no changes. */
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini /** @brief Expand the rectangle in both directions by the specified amount.
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini * Note that this is different from scaling. Negative values wil shrink the
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini * rectangle. If <code>-amount</code> is larger than
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini * half of the width, the X interval will contain only the X coordinate
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini * of the midpoint; same for height. */
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini f[X].expandBy(amount); f[Y].expandBy(amount);
353934d9411d97ad34e4abaa5f78d73bd6dd8b9eRiccardo Bernardini /** @brief Expand the rectangle by the coordinates of the given point.
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz * This will expand the width by the X coordinate of the point in both directions
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz * and the height by Y coordinate of the point. Negative coordinate values will
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz * shrink the rectangle. If <code>-p[X]</code> is larger than half of the width,
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz * the X interval will contain only the X coordinate of the midpoint; same for height. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /// @name Operators
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz /** @brief Offset the rectangle by a vector. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz f[X] += p[X];
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz f[Y] += p[Y];
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Offset the rectangle by the negation of a vector. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz f[X] -= p[X];
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz f[Y] -= p[Y];
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz /** @brief Union two rectangles. */
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz GenericRect<C> &operator|=(GenericRect<C> const &o) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Test for equality of rectangles. */
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz bool operator==(GenericRect<C> const &o) const { return f[X] == o[X] && f[Y] == o[Y]; }
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * @brief Axis-aligned generic rectangle that can be empty.
c864652e7fca4ed7605835d5cb6661dc422cabaaJon A. Cruz * @ingroup Primitives
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz : public boost::optional<typename CoordTraits<C>::RectType>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz , boost::andable< GenericOptRect<C>, typename CoordTraits<C>::RectType
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz typedef typename CoordTraits<C>::IntervalType CInterval;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz typedef typename CoordTraits<C>::OptIntervalType OptCInterval;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz typedef typename CoordTraits<C>::PointType CPoint;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz typedef typename CoordTraits<C>::RectType CRect;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz typedef typename CoordTraits<C>::OptRectType OptCRect;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz GenericOptRect(GenericRect<C> const &a) : Base(CRect(a)) {}
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz GenericOptRect(CPoint const &a, CPoint const &b) : Base(CRect(a, b)) {}
00339f176618a0eebcbb2261306a9cd841ad43ecJon A. Cruz * Creates an empty OptRect when one of the argument intervals is empty.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz GenericOptRect(OptCInterval const &x_int, OptCInterval const &y_int) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz // else, stay empty.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /** @brief Check for emptiness. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool intersects(CRect const &r) const { return r.intersects(*this); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool contains(CRect const &r) const { return *this && (*this)->contains(r); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool intersects(OptCRect const &r) const { return *this && (*this)->intersects(r); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool contains(OptCRect const &r) const { return *this && (*this)->contains(r); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool contains(CPoint const &p) const { return *this && (*this)->contains(p); }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if (!*this) return;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz OptCInterval x = (**this)[X] & b[X], y = (**this)[Y] & b[Y];
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if (x && y) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz GenericOptRect<C> &operator|=(OptCRect const &b) {
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz GenericOptRect<C> &operator&=(OptCRect const &b) {
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruzinline void GenericRect<C>::unionWith(OptCRect const &b) {
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruzinline bool GenericRect<C>::intersects(OptCRect const &r) const {
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz return r && intersects(*r);
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruzinline bool GenericRect<C>::contains(OptCRect const &r) const {
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruz return !r || contains(*r);
2c312e5f8adf7306ce4b41fb6639475df9c3ea87Jon A. Cruzinline std::ostream &operator<<(std::ostream &out, GenericRect<C> const &r) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz} // end namespace Geom
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#endif // LIB2GEOM_SEEN_RECT_H
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz Local Variables:
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz c-file-style:"stroustrup"
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz indent-tabs-mode:nil
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz fill-column:99
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :