Click here to Skip to main content
15,894,955 members
Articles / Programming Languages / C#

Drawing Component to build GIS and CAM applications

Rate me:
Please Sign up or sign in to vote.
4.72/5 (14 votes)
21 Nov 20055 min read 107.9K   8K   123  
An object oriented drawing component for building GIS and CAM applications with multiple views of geometrical model, multiple resolution handling, layers, optimized graphics and more.
// Revision 1.41  2000/01/23 14:09:36  eyalk
// adding error macros + minmax for three elements + change in split()
// and unary_wrapper() functions.
//
// Revision 1.40  1999/10/04 08:23:19  eyalk
// epsilon added
//
// Revision 1.39  1999/07/14 06:20:53  joseph-w
// fixing dependencies
//
// Revision 1.38  1999/06/10 12:04:37  eyalk
// changes before new scanner version
//
// Revision 1.37  1999/04/20 06:55:43  eyalk
// reference to pair type
//
// Revision 1.36  1999/02/16 08:08:48  eyalk
// oop small change
//
// Revision 1.35  1999/02/14 08:58:39  eyalk
// make diff to view changes ...
//
// Revision 1.34  1999/02/04 12:22:40  eyalk
// removing destructor from singleton (have no friends)
//
// Revision 1.33  1999/02/04 11:40:06  eyalk
// template singleton in ey_basics.H
//
// Revision 1.32  1998/12/15 14:37:43  eyalk
// small changes
//
// Revision 1.31  1998/12/15 11:11:09  tamir
// added ifndef for macros : ABS, SDR
//
// Revision 1.30  1998/10/29 09:03:22  joseph-w
// c++ fixes
//
// Revision 1.29  1998/08/24 15:14:58  joseph-w
// fixed timer const warnings
//
// Revision 1.28  1998/08/13 07:35:54  eyalk
// fixing ntos %f -> %g
//
// Revision 1.27  1998/08/09 17:01:36  yaelm
// change <algo.h> to <algorithm>
//
// Revision 1.26  1998/08/04 07:12:52  eyalk
// removing MIN cosmetic changes in box_finder
//
// Revision 1.25  1998/08/03 14:52:42  eyalk
// Aug. 3 98
//
// Revision 1.24  1998/07/21 08:02:58  joseph-w
// #DEFINE word ... conflict with solaris system includes.
//
// Revision 1.23  1998/05/27 12:03:41  eyalk
// Explicit class + rearranging
//
// Revision 1.22  1998/05/19 11:41:30  eyalk
// using iterator_traits
//
// Revision 1.21  1998/04/20 11:38:47  eyalk
// version 2.8.1 adaptations + restructuring
//
// Revision 1.20  1998/03/03 10:09:30  eyalk
// upgrading to gcc2.8.0 and making changes due to panic flagged compilation
//
// Revision 1.19  1998/02/23 15:44:54  eyalk
// printing vector paded with #ifdef for back compatibility with non 2.8 gcc
//

// Revision 1.18  1998/02/23 15:02:26  meirm
// *** empty log message ***
//
// Revision 1.16  1998/02/17 15:27:19  meirm
// changing of compiler to 2.8.0
//
// Revision 1.15  1998/02/17 08:39:26  eyalk
// changes fo the g++ 2.8.0 (typename)
//
// Revision 1.14  1997/11/18 12:38:31  eyalk
// more care to correct machine parameters calculations (using atan2)
// reading map and cosmetics
//
// Revision 1.13  1997/09/11 08:49:17  eyalk
// *** empty log message ***
//
// Revision 1.12  1997/07/29 16:18:35  eyalk
// more functios
//
// Revision 1.11  1997/06/15 12:38:03  eyalk
// Moving points unification to ey_geometry.H and adding printing of list.
//
// Revision 1.10  1997/05/08 07:01:10  eyalk
// more changes
//
// Revision 1.9  1997/04/30 12:51:56  shai
// Changed operator()(const PointType& p0, const PointType& p1) of tk_segment.
//
// Revision 1.8  1997/04/30 08:52:18  shai
// Added tag to tk_segment members.
//
// Revision 1.7  1997/04/15 17:14:58  eyalk
// code improvements
//
// Revision 1.6  1997/03/02 15:19:09  eyalk
// adding the for_each algo.h and returning the SQR SQRDIST ...
//
// Revision 1.5  1997/02/19 07:21:00  eyalk
// updating files for the focus version which have z axis abilities
//
// Revision 1.4  1997/01/22 15:39:52  eyalk
// add constructor to Efeature
//
// Revision 1.3  1997/01/22 14:13:53  shmulik
// Changing the name of Feature class to Efeature
//
// Revision 1.2  1997/01/21 12:50:23  eyalk
// much more templated
//
// Revision 1.1  1996/10/24 09:36:49  eyalk
// Header files which are necessary while working with Eyal classes.
//
// Revision 1.2  1996/05/12 11:20:34  eyalk
// adding to STL the possibility to print any vector.
// correcting the transformation by adding +.5 for rounding.
//
// Revision 1.1  1996/05/05 16:32:26  eyalk
// Initial revision
//

#ifndef _EY_BASICS_HEADER_
#define _EY_BASICS_HEADER_

#include <cstdio>
#include <ctime>
#include <cmath>
#include <cfloat>

#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <utility>
#include <functional>
#include <iterator>

using namespace std;

// commented out by yossi ... causes a compile error with
// system header files sys/fault.h on solaris
//
// Not used anywhere here anyway!!!
//
//#define byte  unsigned char
//#define word  unsigned short int
//#define dword unsigned int

// Error

// macros for fast computation (it apparently faster than inline ...)
#ifndef ABS
#define ABS(x) ((x) < 0 ? -(x) : (x))
#endif
#define ABS_DIFF(a, b) ((a) < (b) ? (b) - (a) : (a) - (b)) // abs(a - b)
#ifndef SQR
#define SQR(x) ((x)*(x))
#endif
#define SQR_DIST(p1, p2) (SQR((p1).x - (p2).x)+SQR((p1).y - (p2).y))

#define BUGPLACE  " File: " << __FILE__ << " Line: " << __LINE__ << endl
#define EY_FATAL_ERROR(x) { cerr << "Error, " << (x) << BUGPLACE; exit(1); }
#define EY_WARNING(x) { cerr << "Warning, " << (x) << BUGPLACE; }

// many times rise a need for min/max for three parameters
template <class T>
inline const T& min(const T& a, const T& b, const T& c)
{
  if (a < b) {
    if (c < a)
      return c;
    else
      return a;
  } else {
    if (c < b)
      return c;
    else
      return b;
  }
}

template <class T>
inline const T& max(const T& a, const T& b, const T& c)
{
  if (b < a) {
    if (a < c)
      return c;
    else
      return a;
  } else {
    if (b < c)
      return c;
    else
      return b;
  }
}

inline double min(double a,double b)
{
	return (a<b) ? a : b;
}

template <class T, class Compare>
inline const T& min(const T& a, const T& b, const T& c, Compare comp)
{
  if (comp(a,b)) {
    if (comp(c,a))
      return c;
    else
      return a;
  } else {
    if (comp(c,b))
      return c;
    else
      return b;
  }
}

template <class T, class Compare>
inline const T& max(const T& a, const T& b, const T& c, Compare comp)
{
  if (b,a) {
    if (comp(a,c))
      return c;
    else
      return a;
  } else {
    if (comp(b,c))
      return c;
    else
      return b;
  }
}

// float epsilon
const double ey_epsilon = FLT_EPSILON;

/** When casting numbers if necessary numbers are truncated when moving
    from float type to integer one.
    The following classes allow numbers to be round instead truncated in these
    cases.
*/

// cast any type by rounding
template <class T>
struct round_cast : unary_function<T, long double> {
  T operator()(long double d) {
    if (d > 0)
      return static_cast<T>(d + .5);
    else
      return static_cast<T>(d - .5);
  }
};

// specialization for float
template <>
struct round_cast<float> : unary_function<float, void>{
  template <class T>
  float operator () (const T& a) { return static_cast<float>(a); }
};

// specialization for double
template <>
struct round_cast<double> : unary_function<double, void> {
  template <class T>
  double operator () (const T& a) { return static_cast<double>(a); }
};

// specialization for long double
template <>
struct round_cast<long double> : unary_function <long double, void> {
  template <class T>
  long double operator () (const T& a) { return static_cast<long double>(a); }
};

// prettier() function causes an object to be print pretty
// iff it has the method - ostream& pretty_print(ostream& out) const {}
// there you should define your pretty printing

template <class T>
class __pretty_print {

  const T& obj;

public:
  __pretty_print(T pobj) : obj(pobj) { }

  friend ostream& operator << (ostream& out, const __pretty_print<T>& pobj)
  {
    return pobj.obj.pretty_print(out);
  }
};

template<class T>
inline __pretty_print<T> prettier(const T& x) { return __pretty_print<T>(x); }


// printing vector (vertically).
template <class T>
inline ostream& operator << (ostream& out, const vector<T>& v)
{
  for (vector<T>::const_iterator it = v.begin(); it != v.end(); ++it) {
    out << *it << endl;
  }
  return out;
}


// printing list (vertically)
template <class T>
inline ostream& operator << (ostream& out, const list<T>& l)
{
  for (list<T>::const_iterator it = l.begin(); it != l.end(); ++it) {
    out << *it << endl;
  }
  return out;
}


// printing map (vertically key + type).
template <class Key, class T, class Compare>
inline ostream& operator << (ostream& out, const map<Key, T, Compare>& m)
{
  for (map<Key, T, Compare>::const_iterator it = m.begin(); it != m.end(); ++it) {
    out << *it << endl;
  }
  return out;
}


// reading map
template <class Key, class T, class Compare>
inline istream& operator >> (istream& in, map<Key, T, Compare>& m)
{
  pair<Key, T> tmp;
  while(in >> tmp)
    m[tmp.first] = tmp.second;

  return in;
}


// printing container which contains containers
template <class ContainerContainer>
void container_of_containers_print(const ContainerContainer& cc,
				   ostream& out, char* sep1, char* sep2)
{
  for (typename ContainerContainer::const_iterator it = cc.begin(); it != cc.end(); ++it) {
    copy((*it).begin(), (*it).end(),
	 ostream_iterator<typename ContainerContainer::value_type::value_type>(out, sep2));
    out << sep1;
  }
}

template <class PointType>
class tk_segment {
  
  ostream&   out;
  string     color;
  int        width;
  string     tag;

public:

  tk_segment(ostream& o, const string& c = string("black"), 
	     int w = 1, string t = "")
    : out(o), color(c), width(w), tag(t)
  {}

  void operator()(const PointType& p0, const PointType& p1)
  {
    out << "$c create line " << p0 << " " << p1
	<< " -fill " << color << " -width " << width;
    if(tag != "")
      out << " -tag " << tag  << endl;
    else 
      out << endl;
  }
  
  void operator()(const pair<PointType, PointType>& s)
  {
    (*this)(s.first, s.second);
  }
  
};


// ---------------------- adding to pair -------------------

// comparing pair by first using the second field
template <class PairType>
class less_second_first : binary_function<PairType, PairType, bool> {
  
public:

  bool operator()(const PairType& a, const PairType& b) const { 
    return a.second < b.second || (!(b.second < a.second) && a.first < b.first); 
  }
};

// printing pair
template <class T1, class T2>
inline ostream& operator << (ostream& out, const pair<T1, T2>& p)
{
  out << p.first << " " << p.second;
  return out;
}

// reading pair
template <class T1, class T2>
inline istream& operator >> (istream& in, pair<T1, T2>& p)
{
  in >> p.first >> p.second;
  return in;
}

// act as reference to pair
template <class T1, class T2>
struct ref_pair {

  typedef T1    first_type;
  typedef T2    second_type;

  const T1& first;
  const T2& second;

  ref_pair (const T1& a, const T2& b)
    : first (a), second (b) {}

  ref_pair(const pair<T1, T2>& p): first(p.first), second (p.second) {}

 // template<class U, class V>
  //ref_pair(const pair<U, V> &p): first(p.first), second (p.second) {}

private:
  ref_pair();
};

template <class T1, class T2>
inline bool operator< (const ref_pair<T1, T2>& x, const ref_pair<T1, T2>& y)
{ return x.first < y.first || (! (y.first < x.first) && x.second < y.second); }

template <class T1, class T2>
inline ref_pair<T1, T2> make_ref_pair (const T1& x, const T2& y)
{ return ref_pair<T1, T2> (x, y); }


// namespace eyk {
// // triple is nacessary many times
// template <class T1, class T2 = T1, class T3 = T2>
// struct triple {
//     T1 first;
//     T2 second;
//     T3 third;
//     triple (const T1& a, const T2& b, const T3& c) :
//            first (a), second (b), third (c) {}
// };

// template <class T1, class T2, class T3>
// inline bool operator== (const triple<T1, T2, T3>& x, const triple<T1, T2, T3>& y)
// { return x.first == y.first && x.second == y.second && x.third == y.third; }

// template <class T1, class T2, class T3>
// inline bool operator< (const triple<T1, T2, T3>& x, const triple<T1, T2, T3>& y)
// {
//     return x.first < y.first ||
//            (! (y.first < x.first) && (x.second < y.second ||
//           (! y.second < x.second) && (x.third < y.third)));
// }

// template <class T1, class T2, class T3>
// inline triple<T1, T2, T3> make_triple (const T1& x, const T2& y, const T3& z)
// { return triple<T1, T2, T3> (x, y, z); }

// }

/** function object for printing container with index where start
    is the strating index
*/
template <class T>
class print_index : public unary_function<T, void> {
  
  int         i;
  ostream&    o;
  const char* d;
     
public:
  print_index(ostream& out, const char *delimiter, int start = 0)
    : i(start), o(out), d(delimiter)
  {}

  void operator() (T x) { o << i++ << " " << x << d; }
};


/** A very simple timer */
class Timer {

public:
  
  // construct timer - if start=true (which is the default)
  // it also start it.
  Timer(bool start = true) 
    : last_val(0), accumulated_time(0), work_status(start)
  {
    if (start)
      last_val = clock();
  };

  // reset the clock and cause it run
  void reset() { 
    accumulated_time = 0;
    work_status = true;
    last_val = clock();
  }

  // reset the clock and stop it
  void reset_stop() {
    accumulated_time = 0;
    work_status = false;
  }
  // read current time
  float read_time() const {
    if (work_status == true) {
      accumulated_time += clock() - last_val;
      last_val = clock();
    }
    return (float)accumulated_time/CLOCKS_PER_SEC;
  }

  // start the clock again after it stopped
  bool start() {
    if (work_status == true) {
      cerr << "warrning: clock restarted while it was already worked\n";
      return false;
    }

    work_status = true;
    last_val = clock();
    return true;
  }

  // stop the clock (not reset it)
  bool stop() {
 
    if (work_status == false) {
      cerr << "warrning: clock stoped while it was not worked\n";
      return false;
    }

    accumulated_time += clock() - last_val;
    work_status = false;
    return true;
  }
  
  friend ostream& operator << (ostream& out, const Timer & timer)
  {
    out << timer.read_time();
    return out;
  }

private:

  mutable clock_t last_val;
  mutable clock_t accumulated_time;
  bool    work_status;
};

// ------------------------ string manipulations ------------------

// convert number to string
inline string ntos(double num)
{
  char buf[1024];
  sprintf(buf, "%g", num);
  return string(buf);
}

// split string according to a seperator and push_back them to a container.
// returns the number of strings and put to the container.
template <class Container>
unsigned split(const string &str, Container& result, const string& seperators)
{
  result.erase(result.begin(), result.end());
  
  bool seperator = true;

  // pass over the characters of the string
  for (string::const_iterator str_it = str.begin(); str_it != str.end(); ++str_it) {
    // search if current char is a seperator
    if (seperators.find(*str_it) != string::npos) {
      // seperator found
      if (!seperator) {
	// previous char was not a seperator
	seperator = true;
      }
    } else {
      // character found
      if (seperator) {
	// previous char was a seperator
	seperator = false;
	result.push_back(string());
	result.back() += *str_it;
      } else {
	// previous char was not a seperator
	// just add char to last string
	result.back() += *str_it;
      }
    }
  }
  return result.size();
}

// join strings from a container according to a seperator to one string.
// return string
template <class Container>
string join(const Container& input, const string& seperator,int sep_num)
{
    if(input.empty())
	return "";
    
    string result = "";
    for (typename Container::const_iterator iter = input.begin(); iter != input.end(); ++iter) {
	result += (*iter) + (sep_num>0?seperator:"");
	sep_num--;
    }
    return result;
}

//  ----------------- wrappers ------------------------

/** create templated singleton - single global instance of a required
    class.
*/
template <class T>
class singleton {

public:
  
  // The instance
  static T& i() {
    static T v;
    return v;
  }

private:

  singleton() { };
  singleton(const singleton&);
};

/** Explicit class allows desired class only to be pass.
    It is by forbidding others to be pass.
    e.g. function f(Explicit<unsigned>) will be called
    only by f(unsigned()) (or f(const unsigned()))
*/
template <class T>
class Explicit {

public:

  // constructor (allows implicit conversions from T to Explicit)
  Explicit(T) {}

  // constructor for others wich calls non existing function by that
  // disallow conversions (revealed only in link time)
  template <class OTHERS>
  Explicit(OTHERS)
  {
    // will appear as error while linking
    Explicit_class_forbids_passing_type_not_desigend_to();
  }
};

// Wrappers for object functions. permits the wrapped objects to be
// passed to algorithms without being copied, thus contains data that
// the algorithm may changed.
// It is like call by reference object function.


template <class Object>
class unary_wrapper : public unary_function<typename Object::argument_type,
		                           typename Object::result_type>
{
  Object&  obj;

public:
  
  unary_wrapper(Object& o) : obj(o) {}

  typename Object::result_type operator()(typename Object::argument_type & a)
  {
    return obj(a);
  }
};

// use the unary_wrap() function to wrap unary object function.
template<class Object>
unary_wrapper<Object> unary_wrap(Object& obj)
{
  return unary_wrapper<Object>(obj);
}

template <class Object>
class binary_wrapper 
  : public binary_function<typename Object::first_argument_type,
                           typename Object::second_argument_type,
                           typename Object::result_type>
{
  Object&  obj;

public:
  
  binary_wrapper(Object& o) : obj(o) {}

  typename Object::result_type operator()
    (typename Object::first_argument_type&  a,
     typename Object::second_argument_type& b)
  {
    return obj(a, b);
  }
};

// use the binary_wrap() function to wrap binary object function.
template<class Object>
binary_wrapper<Object> binary_wrap(Object& obj)
{
  return binary_wrapper<Object>(obj);
}

// --------------------------- STL like --------------------------


// to algorithm
template <class InputIterator1, class InputIterator2, class Function>
Function for_each(InputIterator1 first1, InputIterator1 last1,
		  InputIterator2 first2, Function f)
{
    while (first1 != last1) f(*first1++, *first2++);
    return f;
}

// transform container to itself
template <class InputIterator, class UnaryOperation>
void transform(InputIterator first, InputIterator last,	UnaryOperation op) {
  for ( ; first != last; ++first)
    *first = op(*first);
}

// to functional
// object function having both unary_function and binary_function versions

template <class Arg1, class Arg2, class Result>
struct dual_function {
  typedef Arg1   argument_type;
  typedef Arg1   first_argument_type;
  typedef Arg2   second_argument_type;
  typedef Result result_type;
};

template <class Function>
class func_insert_iterator {
protected:
  Function func;
public:
  typedef output_iterator_tag              iterator_category;
  typedef typename Function::argument_type value_type;
  typedef void        difference_type;
  typedef void        pointer;
  typedef void        reference;

  explicit func_insert_iterator(Function f) : func(f) {}
  func_insert_iterator<Function>&
  operator=(const value_type& value) { 
    func(value);
    return *this;
  }
  func_insert_iterator<Function>& operator*() { return *this; }
  func_insert_iterator<Function>& operator++() { return *this; }
  func_insert_iterator<Function>& operator++(int) { return *this; }
};

template <class Function>
inline func_insert_iterator<Function> func_inserter(Function f) {
  return func_insert_iterator<Function>(f);
}


template <class Container>
class Back_insert_iterator {
protected:
  Container* container;
public:
  typedef output_iterator_tag             iterator_category;
  typedef typename Container::value_type  value_type;
  typedef void                difference_type;
  typedef void                pointer;
  typedef void                reference;

  explicit Back_insert_iterator(Container& x) : container(&x) {}
  Back_insert_iterator<Container>&
  operator=(const value_type& value) { 
    container->push_back(value);
    return *this;
  }
  Back_insert_iterator<Container>& operator*() { return *this; }
  Back_insert_iterator<Container>& operator++() { return *this; }
  Back_insert_iterator<Container>& operator++(int) { return *this; }
};


template <class Container>
inline Back_insert_iterator<Container> Back_inserter(Container& x) {
  return Back_insert_iterator<Container>(x);
}

#endif // _EY_BASICS_HEADER_

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Canada Canada
Baranovsky Eduard has been a software developer for more then 10 years. He has an experence in image processing, computer graphics and distributed systems design.

Comments and Discussions