I am using a data model with classes: Point2D, Point3D, PointGeo:
template <class T>
class Point2D
{
protected:
T x;
T y;
...
};
template <class T>
class Point3D
{
protected:
T x;
T y;
T z;
...
};
template <class T>
class PointGeo
{
protected:
T lat;
T lon;
...
};
To manage instances of these classes the folowing classes allowing loading points from file, adding/removing points, clearing list, printing are used...
List of 2D points
template <class T>
struct TPoints2DList
{
typedef std::vector <Point2D <T> > Type;
};
template <class T>
class Points2DList
{
private:
typename TPoints2DList <T>::Type points;
public:
Points2DList() : points ( 0 ) {}
virtual ~Points2DList() {points.clear();}
Points2DList ( const Points2DList &source );
typename TPoints2DList <T>::Type ::iterator begin() { return points.begin(); }
typename TPoints2DList <T>::Type::const_iterator begin() const { return points.begin(); }
typename TPoints2DList <T>::Type::iterator end() { return points.end(); }
typename TPoints2DList <T>::Type::const_iterator end() const { return points.end(); }
Point2D <T> &operator [] ( int index ) {return points[index];}
const Point2D <T> &operator [] ( int index ) const {return points[index];}
public:
//Overloaded member functions
inline void clear() {points.clear();};
inline void pop_back() {points.pop_back();}
inline void push_back ( Point2D <T> p ) { points.push_back ( p );}
inline unsigned int size() const {return points.size();}
public:
//Other methods
void loadPointsFromFile ( const char *file);
...
}
List of 3D points
template <class T>
struct TPoints3DList
{
typedef std::vector <Point3D <T> > Type;
};
template <class T>
class Points3DList
{
private:
typename TPoints3DList <T>::Type points;
public:
Points3DList() : points ( 0 ) {}
virtual ~Points2DList() {points.clear();}
Points3DList ( const Points3DList &source );
typename TPoints3DList <T>::Type ::iterator begin() { return points.begin(); }
typename TPoints3DList <T>::Type::const_iterator begin() const { return points.begin(); }
typename TPoints3DList <T>::Type::iterator end() { return points.end(); }
typename TPoints3DList <T>::Type::const_iterator end() const { return points.end(); }
Point3D <T> &operator [] ( int index ) {return points[index];}
const Point3D <T> &operator [] ( int index ) const {return points[index];}
public:
inline void clear() {points.clear();};
inline void pop_back() {points.pop_back();}
inline void push_back ( Point3D <T> p ) { points.push_back ( p );}
inline unsigned int size() const {return points.size();}
public:
//Other methods
void loadPointsFromFile ( const char *file);
...
}
Source code of PointGeo class is similar...
So differences in the code between the classes are small. They differ in methods for loading, printing, saving data.
Would it be inappropriate to design a class replacing all three classes? How to create methods for loading, printing data specific for the data type?
The similar situation occurs for the dynamic alocation: Node2D, Node3D,... classes. Class Node2D stores some topological relationships and using pointers to other nodes or faces... In such case all three classes will have a different destructor...
List of 2D points
template <class T>
struct TNodes2DList
{
typedef std::vector <Node2D <T> *> Type;
};
Thank you very much for your comments and suggestions. I am writing geometric library and thinking about the most suitable data model.
You could put the I/O operations directly to Point2D Point3D types. Then the you wouldn't have to create additional list class since printing/reading would be as simple as:
for (std::vector<Point3D>::iterator i = a.begin; i != a.end(); ++i) {
i->print_to_file(file);
}
If this isn't viable, at least the same list class could be used as template to serve both Point3D and Point2D
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With