Compare commits
No commits in common. "main" and "master" have entirely different histories.
8 changed files with 88 additions and 194 deletions
16
Makefile
16
Makefile
|
|
@ -1,21 +1,13 @@
|
|||
.PHONY: default
|
||||
default: dashing dashing.omp
|
||||
default: dashing
|
||||
|
||||
.PHONY: bench
|
||||
bench: dashing
|
||||
perf stat --log-fd=2 ./dashing -b -s .1 data/HWOOD6E1.pat data/sf.seg
|
||||
|
||||
dashing: main.cc dashing.cc dashing.hh parse_numbers.hh contours_and_segments.hh
|
||||
+g++ -W -Wall -O2 -g -std=c++20 $(filter %.cc, $^) -o $@ -flto -DNDEBUG
|
||||
g++ -W -Wall -O2 -g -std=c++11 $(filter %.cc, $^) -o $@ -lboost_random
|
||||
dashing-noopt: main.cc dashing.cc dashing.hh parse_numbers.hh contours_and_segments.hh
|
||||
+g++ -W -Wall -O0 -g -std=c++20 $(filter %.cc, $^) -o $@
|
||||
g++ -W -Wall -O0 -g -std=c++11 $(filter %.cc, $^) -o $@ -lboost_random
|
||||
dashing-clang: main.cc dashing.cc dashing.hh parse_numbers.hh
|
||||
+clang++ -W -Wall -O2 -g -std=c++20 $(filter %.cc, $^) -o $@ -flto -DNDEBUG
|
||||
dashing.pgo.0: main.cc dashing.cc dashing.hh parse_numbers.hh contours_and_segments.hh
|
||||
+g++ -W -Wall -O2 -g -std=c++20 $(filter %.cc, $^) -o $@ -flto -DNDEBUG -fprofile-generate
|
||||
dashing.pgo.1: dashing.pgo.0 main.cc dashing.cc dashing.hh parse_numbers.hh contours_and_segments.hh
|
||||
./dashing.pgo.0 -b -s .002 data/HWOOD6E1.pat data/sf.seg
|
||||
+g++ -W -Wall -O2 -g -std=c++20 $(filter %.cc, $^) -o $@ -flto -DNDEBUG -fprofile-use
|
||||
|
||||
dashing.omp: main.cc dashing.cc dashing.hh parse_numbers.hh contours_and_segments.hh
|
||||
+g++ -W -Wall -O2 -g -std=c++20 $(filter %.cc, $^) -o $@ -flto -DNDEBUG -fopenmp -DDASHING_OMP
|
||||
clang++ -W -Wall -O2 -g -std=c++11 $(filter %.cc, $^) -o $@ -lboost_random
|
||||
|
|
|
|||
28
README.md
28
README.md
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
License: permissive (zlib); see source files for additional details.
|
||||
|
||||
On a i5-1235U in multithreaded benchmark mode, it runs at over 3.3 billion dashes per second:
|
||||
On a i5-3320M in benchmark mode, it runs at over 175 million dashes per second:
|
||||
```
|
||||
$ time ./dashing.omp -b -s .002 data/HWOOD6E1.pat data/sf.seg
|
||||
2822685873
|
||||
real 0m0.851s
|
||||
$ time ./dashing -b -s .01 data/HWOOD6E1.pat data/sf.seg
|
||||
111430525
|
||||
user 0m0.616s
|
||||
```
|
||||
|
||||

|
||||
|
|
@ -31,7 +31,7 @@ I would be interested in passing this project to a new maintainer.
|
|||
The winding rule `wr` defines which regions are in the interior of the contours.
|
||||
For each dash or dot in the resulting hatch, `cb` is called with the output segment.
|
||||
|
||||
`xyhatch(const HatchPattern&, const C &segments, Cb cb, const char *wr)`:
|
||||
`xyhatch(const HatchPattern&, const C &segments, Cb cb, const char \*wr)`:
|
||||
The container C holds segments which must define a set of closed
|
||||
contours.
|
||||
The winding rule `wr` defines which regions are in the interior of the contours.
|
||||
|
|
@ -39,7 +39,7 @@ I would be interested in passing this project to a new maintainer.
|
|||
|
||||
`HatchPattern::FromFile`: Read a hatch pattern from a file.
|
||||
|
||||
`parse_numbers(std::string line)`: Read a comma and/or space-separated
|
||||
`parse\_numbers(std::string line)`: Read a comma and/or space-separated
|
||||
sequence of numbers into a vector
|
||||
|
||||
`SegmentsFromFile`, `ContoursFromFile`, `ContourToSegments`, `ContoursToSegments`: Read and convert segments and contours
|
||||
|
|
@ -51,22 +51,6 @@ Useful winding rules include:
|
|||
|
||||
but any predicate of a single integer may be used.
|
||||
|
||||
### Parallel API
|
||||
These APIs are available if built with `-fopenmp -DDASHING_OMP`
|
||||
|
||||
`xyhatch_omp(const HatchPattern&, It start, It end, Cb cb, Wr wr)`:
|
||||
Iterators `start`..`end` define a range of segments, which must define a set of closed contours.
|
||||
The winding rule `wr` defines which regions are in the interior of the contours.
|
||||
For each dash or dot in the resulting hatch, `cb` is called with the output segment and the thread ID.
|
||||
|
||||
`xyhatch_omp(const HatchPattern&, const C &segments, Cb cb, Wr wr)`:
|
||||
The container C holds segments which must define a set of closed
|
||||
contours.
|
||||
The winding rule `wr` defines which regions are in the interior of the contours.
|
||||
For each dash or dot in the resulting hatch, `cb` is called with the output segment and the thread ID.
|
||||
|
||||
### Other APIs
|
||||
|
||||
Other items in the header files are implementation details.
|
||||
|
||||
## Demo program
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ typedef std::vector<Contour> Contours;
|
|||
|
||||
void ContourToSegments(Segments &dest,
|
||||
/* EXPLICIT COPY */ Contour src,
|
||||
F jitter = 0)
|
||||
double jitter = 0)
|
||||
{
|
||||
if(jitter)
|
||||
{
|
||||
|
|
@ -32,7 +32,7 @@ void ContourToSegments(Segments &dest,
|
|||
dest.emplace_back(Segment{src[i-1], src[0], false});
|
||||
}
|
||||
|
||||
void ContoursToSegments(Segments &dest, Contours const &src, F jitter=0)
|
||||
void ContoursToSegments(Segments &dest, Contours const &src, double jitter=0)
|
||||
{
|
||||
dest.clear();
|
||||
|
||||
|
|
@ -62,14 +62,14 @@ Contours ContoursFromFile(std::istream &fi)
|
|||
return result;
|
||||
}
|
||||
|
||||
Segments SegmentsFromFile(std::istream &fi, F jitter) {
|
||||
Segments SegmentsFromFile(std::istream &fi, double jitter) {
|
||||
auto && contours = ContoursFromFile(fi);
|
||||
auto result = Segments{};
|
||||
ContoursToSegments(result, contours, jitter);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Segment> SegmentsFromFile(const char *filename, F jitter) {
|
||||
std::vector<Segment> SegmentsFromFile(const char *filename, double jitter) {
|
||||
std::fstream fi(filename);
|
||||
return SegmentsFromFile(fi, jitter);
|
||||
}
|
||||
|
|
|
|||
50
dashing.cc
50
dashing.cc
|
|
@ -2,41 +2,37 @@
|
|||
#include "dashing.hh"
|
||||
namespace dashing
|
||||
{
|
||||
std::vector<F> parse_numbers(std::string line) {
|
||||
std::vector<double> parse_numbers(std::string line) {
|
||||
boost::algorithm::replace_all(line, ",", " ");
|
||||
std::istringstream fi(line);
|
||||
std::vector<F> result;
|
||||
F d;
|
||||
while((fi >> d)) {
|
||||
result.push_back(d);
|
||||
for (auto p = fi.peek(); p == ',' || isspace(p); p = fi.peek()) {
|
||||
fi.get();
|
||||
}
|
||||
}
|
||||
std::vector<double> result;
|
||||
double d;
|
||||
while((fi >> d)) result.push_back(d);
|
||||
return result;
|
||||
}
|
||||
|
||||
PSMatrix PSMatrix::inverse() const {
|
||||
auto i = F(1.) / determinant();
|
||||
auto i = 1. / determinant();
|
||||
return PSMatrix{d*i, -b*i, -c*i, a*i, i*(c*f-e*d), i*(b*e-a*f)};
|
||||
}
|
||||
|
||||
PSMatrix Translation(F x, F y) {
|
||||
PSMatrix Translation(double x, double y) {
|
||||
PSMatrix r{1.,0.,0.,1.,x,y};
|
||||
return r;
|
||||
}
|
||||
|
||||
PSMatrix Rotation(F theta) {
|
||||
F c = cos(theta), s = sin(theta);
|
||||
PSMatrix Rotation(double theta) {
|
||||
double c = cos(theta), s = sin(theta);
|
||||
PSMatrix r{c,s,-s,c,0.,0.};
|
||||
return r;
|
||||
}
|
||||
|
||||
PSMatrix XSkew(F xk) {
|
||||
PSMatrix XSkew(double xk) {
|
||||
PSMatrix r{1.,0.,xk,1.,0.,0.};
|
||||
return r;
|
||||
}
|
||||
|
||||
PSMatrix YScale(F ys) {
|
||||
PSMatrix YScale(double ys) {
|
||||
PSMatrix r{1.,0.,0.,ys,0.,0.};
|
||||
return r;
|
||||
}
|
||||
|
|
@ -52,31 +48,21 @@ PSMatrix operator*(const PSMatrix &m1, const PSMatrix m2) {
|
|||
return r;
|
||||
}
|
||||
|
||||
static F radians(F degrees) { return degrees * acos(0) / 90.; }
|
||||
static double radians(double degrees) { return degrees * acos(0) / 90.; }
|
||||
|
||||
Dash::Dash(F th, F x0, F y0, F dx, F dy,
|
||||
const std::vector<F>::const_iterator dbegin,
|
||||
const std::vector<F>::const_iterator dend)
|
||||
: dash{dbegin, dend} {
|
||||
Dash::Dash(double th, double x0, double y0, double dx, double dy,
|
||||
const std::vector<double>::const_iterator dbegin,
|
||||
const std::vector<double>::const_iterator dend) : dash(dbegin, dend) {
|
||||
auto s = 0.;
|
||||
for(size_t i = 0; i < dash.size(); i++) {
|
||||
bool is_negative = std::signbit(dash[i]);
|
||||
bool index_is_odd = (i % 2) != 0;
|
||||
if(is_negative != index_is_odd) {
|
||||
throw std::invalid_argument("not a supported dash specification (but probably valid)");
|
||||
}
|
||||
dash[i] = std::abs(dash[i]);
|
||||
}
|
||||
if (dash.size() % 2) dash.push_back(0);
|
||||
for(auto d : dash) { sum.push_back(s); s += d; }
|
||||
for(auto d : dash) { sum.push_back(s); s += fabs(d); }
|
||||
sum.push_back(s);
|
||||
|
||||
tr = Translation(x0, y0) * Rotation(th) * XSkew(dx / dy) * YScale(dy);
|
||||
tf = tr.inverse();
|
||||
}
|
||||
|
||||
Dash Dash::FromString(const std::string &line, F scale) {
|
||||
std::vector<F> words = parse_numbers(line);
|
||||
Dash Dash::FromString(const std::string &line, double scale) {
|
||||
std::vector<double> words = parse_numbers(line);
|
||||
if(words.size() < 5)
|
||||
throw std::invalid_argument("not a valid dash specification");
|
||||
for(auto i = words.begin() + 1; i != words.end(); i++) *i *= scale;
|
||||
|
|
|
|||
127
dashing.hh
127
dashing.hh
|
|
@ -18,47 +18,43 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef DASHING_H
|
||||
#define DASHING_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <span>
|
||||
#if defined(DASHING_OMP)
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "dashing_F.hh"
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
|
||||
namespace dashing
|
||||
{
|
||||
|
||||
struct PSMatrix {
|
||||
F a, b, c, d, e, f;
|
||||
double a, b, c, d, e, f;
|
||||
|
||||
PSMatrix inverse() const;
|
||||
F determinant() const { return a * d - b * c; }
|
||||
double determinant() const { return a * d - b * c; }
|
||||
};
|
||||
|
||||
PSMatrix Translation(F x, F y);
|
||||
PSMatrix Rotation(F theta);
|
||||
PSMatrix XSkew(F xk);
|
||||
PSMatrix YScale(F ys);
|
||||
PSMatrix Translation(double x, double y);
|
||||
PSMatrix Rotation(double theta);
|
||||
PSMatrix XSkew(double xk);
|
||||
PSMatrix YScale(double ys);
|
||||
|
||||
struct Point { F x, y; };
|
||||
struct Point { double x, y; };
|
||||
inline Point operator*(const Point &p, const PSMatrix &m) {
|
||||
return Point{ p.x*m.a + p.y*m.c + m.e,
|
||||
p.x*m.b + p.y*m.d + m.f };
|
||||
}
|
||||
inline Point operator*(const Point &p, F d)
|
||||
inline Point operator*(const Point &p, double d)
|
||||
{
|
||||
return Point{ p.x * d, p.y * d };
|
||||
}
|
||||
inline Point operator*(F d, const Point &p)
|
||||
inline Point operator*(double d, const Point &p)
|
||||
{
|
||||
return Point{ p.x * d, p.y * d };
|
||||
}
|
||||
|
|
@ -71,17 +67,17 @@ PSMatrix operator*(const PSMatrix &m1, const PSMatrix m2);
|
|||
|
||||
struct Dash {
|
||||
PSMatrix tr, tf;
|
||||
std::vector<F> dash, sum;
|
||||
std::vector<double> dash, sum;
|
||||
|
||||
Dash(F th, F x0, F y0, F dx, F dy,
|
||||
const std::vector<F>::const_iterator dbegin,
|
||||
const std::vector<F>::const_iterator dend);
|
||||
Dash(double th, double x0, double y0, double dx, double dy,
|
||||
const std::vector<double>::const_iterator dbegin,
|
||||
const std::vector<double>::const_iterator dend);
|
||||
|
||||
static Dash FromString(const std::string &line, F scale);
|
||||
static Dash FromString(const std::string &line, double scale);
|
||||
};
|
||||
|
||||
struct Segment { Point p, q; bool swapped; };
|
||||
struct Intersection { F u; bool positive; };
|
||||
struct Intersection { double u; bool positive; };
|
||||
inline bool operator<(const Intersection &a, const Intersection &b)
|
||||
{
|
||||
return a.u < b.u;
|
||||
|
|
@ -94,16 +90,16 @@ inline void ysort(Segment &s) {
|
|||
std::swap(s.p, s.q);
|
||||
}
|
||||
|
||||
inline int intceil(F x) { return int(ceil(x)); }
|
||||
inline int intfloor(F x) { return int(floor(x)); }
|
||||
inline double intceil(double x) { return int(ceil(x)); }
|
||||
inline double intfloor(double x) { return int(floor(x)); }
|
||||
|
||||
inline F pythonmod(F a, F b) {
|
||||
inline double pythonmod(double a, double b) {
|
||||
auto r = a - floor(a / b) * b;
|
||||
if(r == b) return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
inline size_t utoidx(const Dash &d, F u, F &o) {
|
||||
inline size_t utoidx(const Dash &d, double u, double &o) {
|
||||
u = pythonmod(u, d.sum.back());
|
||||
for(size_t i = 1; i != d.sum.size(); i++) {
|
||||
if(u < d.sum[i]) { o = u - d.sum[i-1]; return i-1; }
|
||||
|
|
@ -112,30 +108,26 @@ inline size_t utoidx(const Dash &d, F u, F &o) {
|
|||
}
|
||||
|
||||
template<class Cb>
|
||||
void uvdraw(const Dash &pattern, F v, F u1, F u2, Cb cb) {
|
||||
void uvdraw(const Dash &pattern, double v, double u1, double u2, Cb cb) {
|
||||
if(pattern.dash.empty()) { cb(v, u1, u2); return; }
|
||||
F o;
|
||||
double o;
|
||||
auto i = utoidx(pattern, u1, o);
|
||||
const auto pi = pattern.dash[i];
|
||||
if(i % 2 == 0) { cb(v, u1, std::min(u2, u1+pi-o)); u1 += pi-o; }
|
||||
const auto &pi = pattern.dash[i];
|
||||
if(pi >= 0) { cb(v, u1, std::min(u2, u1+pi-o)); u1 += pi-o; }
|
||||
else { u1 -= pi+o; }
|
||||
i++;
|
||||
if(i % 2) {
|
||||
u1 += pattern.dash[i];
|
||||
i++;
|
||||
}
|
||||
i = i + 1;
|
||||
if(i == pattern.dash.size()) i = 0;
|
||||
for(auto u = u1; u < u2;) {
|
||||
if(i >= pattern.dash.size()) i = 0;
|
||||
const auto pi = pattern.dash[i];
|
||||
cb(v, u, std::min(u2, u+pi));
|
||||
u += pi;
|
||||
u += pattern.dash[i+1];
|
||||
i+=2;
|
||||
const auto &pi = pattern.dash[i];
|
||||
if(pi >= 0) { cb(v, u, std::min(u2, u+pi)); u += pi; }
|
||||
else { u -= pi; }
|
||||
i = i + 1;
|
||||
if(i == pattern.dash.size()) i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Cb, class Wr>
|
||||
void uvspans(const Dash &pattern, std::vector<Segment> & segments, Cb cb, std::vector<Intersection> &uu, Wr wr) {
|
||||
void uvspans(const Dash &pattern, std::vector<Segment> && segments, Cb cb, std::vector<Intersection> &uu, Wr wr) {
|
||||
if(segments.empty()) return; // no segments
|
||||
|
||||
for(auto &s : segments) ysort(s);
|
||||
|
|
@ -181,16 +173,16 @@ void uvspans(const Dash &pattern, std::vector<Segment> & segments, Cb cb, std::v
|
|||
segments_begin ++;
|
||||
}
|
||||
|
||||
for(const auto &s : std::span(heap_begin, heap_end)) {
|
||||
for(const auto &s : boost::make_iterator_range(heap_begin, heap_end)) {
|
||||
auto du = s.q.x - s.p.x;
|
||||
auto dv = s.q.y - s.p.y;
|
||||
assert(dv);
|
||||
uu.push_back(
|
||||
if(dv) uu.push_back(
|
||||
Intersection{s.p.x + du * (v - s.p.y) / dv,s.swapped});
|
||||
}
|
||||
std::sort(uu.begin(), uu.end());
|
||||
int winding = 0;
|
||||
F old_u = -std::numeric_limits<F>::infinity();
|
||||
double old_u = -std::numeric_limits<double>::infinity();
|
||||
for(const auto &isect : uu) {
|
||||
if(wr(winding)) uvdraw(pattern, v, old_u, isect.u, cb);
|
||||
winding += 2*isect.positive - 1;
|
||||
|
|
@ -201,16 +193,14 @@ void uvspans(const Dash &pattern, std::vector<Segment> & segments, Cb cb, std::v
|
|||
|
||||
struct HatchPattern {
|
||||
std::vector<Dash> d;
|
||||
static HatchPattern FromFile(std::istream &fi, F scale) {
|
||||
static HatchPattern FromFile(std::istream &fi, double scale) {
|
||||
HatchPattern result;
|
||||
|
||||
std::string line;
|
||||
while(getline(fi, line)) {
|
||||
auto i = line.find(";");
|
||||
if(i != line.npos) line.erase(i, line.npos);
|
||||
while(!line.empty() && isspace(line.back())) {
|
||||
line.pop_back();
|
||||
}
|
||||
boost::algorithm::trim(line);
|
||||
if(line.empty()) continue;
|
||||
if(line[0] == '*') continue;
|
||||
result.d.push_back(Dash::FromString(line, scale));
|
||||
|
|
@ -218,34 +208,34 @@ struct HatchPattern {
|
|||
return result;
|
||||
}
|
||||
|
||||
static HatchPattern FromFile(const char *filename, F scale) {
|
||||
static HatchPattern FromFile(const char *filename, double scale) {
|
||||
std::ifstream fi(filename);
|
||||
return FromFile(fi, scale);
|
||||
}
|
||||
};
|
||||
|
||||
template<class It, class Cb, class Wr>
|
||||
void xyhatch(const Dash &pattern, It start, It end, Cb cb, Wr wr) {
|
||||
std::vector<Segment> uvsegments;
|
||||
uvsegments.reserve(end-start);
|
||||
|
||||
std::vector<Intersection> uu;
|
||||
uu.reserve(8);
|
||||
|
||||
void xyhatch(const Dash &pattern, It start, It end, Cb cb, std::vector<Segment> &uvsegments, std::vector<Intersection> &uu, Wr wr) {
|
||||
uvsegments.clear();
|
||||
bool swapped = pattern.tf.determinant() < 0;
|
||||
std::transform(start, end, std::back_inserter(uvsegments),
|
||||
[&](const Segment &s)
|
||||
{ return Segment{s.p * pattern.tf, s.q * pattern.tf, swapped != s.swapped };
|
||||
});
|
||||
uvspans(pattern, uvsegments, [&](F v, F u1, F u2) {
|
||||
uvspans(pattern, std::move(uvsegments), [&](double v, double u1, double u2) {
|
||||
Point p{u1, v}, q{u2, v};
|
||||
cb(Segment{ p * pattern.tr, q * pattern.tr, false });
|
||||
Segment xy{ p * pattern.tr, q * pattern.tr, false };
|
||||
cb(xy);
|
||||
}, uu, wr);
|
||||
}
|
||||
|
||||
template<class It, class Cb, class Wr>
|
||||
void xyhatch(const HatchPattern &pattern, It start, It end, Cb cb, Wr wr) {
|
||||
for(const auto &i : pattern.d) xyhatch(i, start, end, cb, wr);
|
||||
std::vector<Segment> uvsegments;
|
||||
uvsegments.reserve(end-start);
|
||||
std::vector<Intersection> uu;
|
||||
uu.reserve(8);
|
||||
for(const auto &i : pattern.d) xyhatch(i, start, end, cb, uvsegments, uu, wr);
|
||||
}
|
||||
|
||||
template<class C, class Cb, class Wr>
|
||||
|
|
@ -253,20 +243,5 @@ void xyhatch(const HatchPattern &pattern, const C &c, Cb cb, Wr wr) {
|
|||
xyhatch(pattern, c.begin(), c.end(), cb, wr);
|
||||
}
|
||||
|
||||
#if defined(DASHING_OMP)
|
||||
template<class It, class Cb, class Wr>
|
||||
void xyhatch_omp(const HatchPattern &pattern, It start, It end, Cb cb, Wr wr) {
|
||||
#pragma omp parallel for
|
||||
for(const auto &i : pattern.d) {
|
||||
int iam = omp_get_thread_num();
|
||||
xyhatch(i, start, end, [iam, &cb](Segment s) { cb(s, iam); }, wr);
|
||||
}
|
||||
}
|
||||
template<class C, class Cb, class Wr>
|
||||
void xyhatch_omp(const HatchPattern &pattern, const C &c, Cb cb, Wr wr) {
|
||||
xyhatch_omp(pattern, c.begin(), c.end(), cb, wr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
|||
26
dashing_F.hh
26
dashing_F.hh
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Jeff Epler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgement in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
namespace dashing
|
||||
{
|
||||
|
||||
typedef float F;
|
||||
}
|
||||
23
main.cc
23
main.cc
|
|
@ -20,12 +20,6 @@ freely, subject to the following restrictions:
|
|||
|
||||
// demo and benchmark program for dashing
|
||||
|
||||
#include <new>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#if defined(DASHING_OMP)
|
||||
#include <omp.h>
|
||||
#endif
|
||||
#include "dashing.hh"
|
||||
#include "contours_and_segments.hh"
|
||||
|
||||
|
|
@ -91,20 +85,9 @@ int main(int argc, char **argv) {
|
|||
if(xit) return 0;
|
||||
|
||||
if(bench) {
|
||||
#if defined(DASHING_OMP)
|
||||
struct per_thread_count_type {
|
||||
alignas(std::hardware_destructive_interference_size) size_t n;
|
||||
};
|
||||
auto max_threads = omp_get_max_threads();
|
||||
std::vector<per_thread_count_type> thread_nseg(max_threads, per_thread_count_type{0});
|
||||
auto count_seg = [&thread_nseg](const Segment &s, int iam) { (void)s; thread_nseg[iam].n++; };
|
||||
xyhatch_omp(h, s, count_seg, [](int i) { return i != 0; } );
|
||||
size_t nseg = std::accumulate(thread_nseg.begin(), thread_nseg.end(), size_t{}, [](size_t a, const per_thread_count_type &b) { return a + b.n; });
|
||||
#else
|
||||
size_t nseg{};
|
||||
auto count_seg = [&nseg](const Segment &s) { (void)s; nseg ++; };
|
||||
xyhatch(h, s, count_seg, [](int i) { return i != 0; } );
|
||||
#endif
|
||||
int nseg = 0;
|
||||
auto print_seg = [&nseg](const Segment &s) { (void)s; nseg ++; };
|
||||
xyhatch(h, s, print_seg, [](int i) { return i != 0; } );
|
||||
std::cout << nseg << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "dashing_F.hh"
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
namespace dashing
|
||||
{
|
||||
std::vector<F> parse_numbers(std::string line);
|
||||
std::vector<double> parse_numbers(std::string line);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue