/ dashing.cc
dashing.cc
 1  #include "parse_numbers.hh"
 2  #include "dashing.hh"
 3  namespace dashing
 4  {
 5  std::vector<double> parse_numbers(std::string line) {
 6      boost::algorithm::replace_all(line, ",", " ");
 7      std::istringstream fi(line);
 8      std::vector<double> result;
 9      double d;
10      while((fi >> d)) result.push_back(d);
11      return result;
12  }
13  
14  PSMatrix PSMatrix::inverse() const {
15      auto i = 1. / determinant();
16      return PSMatrix{d*i, -b*i, -c*i, a*i, i*(c*f-e*d), i*(b*e-a*f)};
17  }
18  
19  PSMatrix Translation(double x, double y) {
20      PSMatrix r{1.,0.,0.,1.,x,y};
21      return r;
22  }
23  
24  PSMatrix Rotation(double theta) {
25      double c = cos(theta), s = sin(theta);
26      PSMatrix r{c,s,-s,c,0.,0.};
27      return r;
28  }
29  
30  PSMatrix XSkew(double xk) {
31      PSMatrix r{1.,0.,xk,1.,0.,0.};
32      return r;
33  }
34  
35  PSMatrix YScale(double ys) {
36      PSMatrix r{1.,0.,0.,ys,0.,0.};
37      return r;
38  }
39  
40  PSMatrix operator*(const PSMatrix &m1, const PSMatrix m2) {
41      PSMatrix r{
42              m2.a * m1.a + m2.b * m1.c,
43              m2.a * m1.b + m2.b * m1.d,
44              m2.c * m1.a + m2.d * m1.c,
45              m2.c * m1.b + m2.d * m1.d,
46              m2.e * m1.a + m2.f * m1.c + m1.e,
47              m2.e * m1.b + m2.f * m1.d + m1.f};
48      return r;
49  }
50  
51  static double radians(double degrees) { return degrees * acos(0) / 90.; }
52  
53  Dash::Dash(double th, double x0, double y0, double dx, double dy,
54          const std::vector<double>::const_iterator dbegin,
55          const std::vector<double>::const_iterator dend) : dash(dbegin, dend) {
56      auto s = 0.;
57      for(auto d : dash) { sum.push_back(s); s += fabs(d); }
58      sum.push_back(s);
59  
60      tr = Translation(x0, y0) * Rotation(th) * XSkew(dx / dy) * YScale(dy);
61      tf = tr.inverse();
62  }
63  
64  Dash Dash::FromString(const std::string &line, double scale) {
65      std::vector<double> words = parse_numbers(line);
66      if(words.size() < 5)
67          throw std::invalid_argument("not a valid dash specification");
68      for(auto i = words.begin() + 1; i != words.end(); i++) *i *= scale;
69      return Dash(radians(words.at(0)), words.at(1), words.at(2), words.at(3),
70          words.at(4), words.begin() + 5, words.end());        
71  }
72  
73  }