I have a file full of data that I need to operate on. Each line of this file contains floating point numbers (represented as strings of course) like this:
x1 y1 z1 x2 y2 z2 x3 y3 z3 r1 g1 b1 r2 g2 b2 r3 g3 b3
each line represents 3 different objects that I need to create, like:
Foo foo1(x1,y1,z1,r1,g1,b1);
Foo foo2(x2,y2,z2,r2,g2,b2);
Foo foo3(x3,y3,z3,r3,g3,b3);
the twist is that:
I want to ONLY create objects if they haven't been created yet. if I've already made a
Foo
with those exact same 6 floats, instead of creating a newFoo
I want to just retrieve that object I alr开发者_开发问答eady made.The data in the file is unreliably delimited -- there could be any number of spaces or tabs between the different numbers.
Before I realized this issue with the spacing, I was splitting each line I read from the file into strings, concatenating the strings that represented each foo, and then using a std::map<std::string,int>
to test for uniqueness, where the int returned by the map represented an index into a std::vector<Foo*>
that I was pushing pointers to each Foo
I was creating into. This fails when the spacing isn't consistent.
all I can think of right now is doing something like:
http://codepad.org/hLhFzhPh (for example) but that seems completely screwy. I also tried making a struct of 6 floating point values, overloading operator>>
to read from a stringstream into it, and then making a map<weirdstruct,int>
but I didn't really know how to overload operator<
to make this work.
Anyway, this seems like it should be easy and I just don't have a clue. Any ideas?
1: Use an std::set<Foo>
to record what you've already constructed. The std::map
+ std::vector
solution is both unreliable and, when fixed, overkill.
2: The following skips over any leading spaces in the input:
double x;
std::cin >> x;
and similar for any std::istream
.
I think I'd convert the inputs to real floating point before comparing. With floating point numbers, differences in the string representation don't necessarily signify differences in the actual value. Just for example, 12345
is equal to 1.2345e4
.
Something like this if you just want a quick solution.
std::stringstream sIn(theline);
std::stringstream sOut;
std::string temp;
while (sIn >> temp) sOut << temp << " ";
std::string fixedline = sOut.str();
The problem I see is finding an exact match since you are using floating point numbers.
I suggest adding an operator==(x,y,z,r,g,b)
to Foo
. Place all your Foo
objects into a container and compare them using the operator==()
, to see if a Foo
object has already been created.
An alternative method is to factor out the <x,y,z,r,g,b>
into a parent structure. Create a container of these. When you create a Foo
object, put an instance into the container. You can search the container before you create the next Foo
instance.
I also suggest transposing the data file so that each line contains only one vector of x,y,z,r,g,b. Sort the file. Remove duplicates before giving it to your program. Use applications outside of your program to do this (preferred). Cygwin and Linux have some nice utilities for sorting and removing duplicates.
Edit1: Example 3D point with input operator (untested)
ifndef POINT3D_HPP
#include <iostream>
#include <cmath>
class Point3d
{
public:
Point3d(double x = 0.0, double y = 0.0, double z = 0.0)
: m_x(x), m_y(y), m_z(z)
{ ; }
Point3d(const Point3d& p3d)
: m_x(p3d.m_x), m_y(p3d.m_y), m_z(p3d.m_z)
{ ; }
friend std::istream& operator>>(std::istream& inp, Point3d& p3d);
bool operator==(const Point3d& p) const
{
return (std::fabs(m_x - p.m_x) < 5.0E-5)
&& (std::fabs(m_y - p.m_y) < 5.0E-5)
&& (std::fabs(m_z - p.m_z) < 5.0E-5);
}
private:
double m_x;
double m_y;
double m_z;
};
inline std::istream&
operator>>(std::istream& inp, Point3d& p)
{
inp >> p.m_x;
inp >> p.m_y;
inp >> p.m_z;
return inp;
}
#endif // POINT3D_HPP
class Foo
: public Point3d
{
public:
Foo(double x, double y, double z,
double r, double g, double b)
: Point3d(x, y, z),
m_r(r), m_g(g), m_b(b)
{ ; }
Foo(const Point3d& p3d,
double r, double g, double b)
: Point3d(p3d),
m_r(r), m_g(g), m_b(b)
{ ; }
double m_r, m_g, m_b;
};
Reading of the data file becomes something like this:
std::ifstream data_file("data.bin");
Point3d p1;
Point3d p2;
Point3d p3;
// Input the first 3 points on the line.
data_file >> p1;
data_file >> p2;
data_file >> p3;
// Or: data_file >> p1 >> p2 >> p3
// Before creating a Foo:
std::vector<Point3d> existing_points;
std::vector<Point3d>::const_iterator iter;
bool is_duplicate = false;
for (iter = existing_points.begin();
iter != existing_points.end();
++iter)
{
if (*iter == p1)
{
is_duplicate = true;
break;
}
}
if (! is_duplicate)
{
existing_points.push_back(p1);
// Create a new Foo
}
The color values can be treated in a very similar fashion (so similar, you could just change member names and class names).
精彩评论