1 |
|
#include <vector> |
2 |
|
#include <libutil/Debug.hxx> |
3 |
|
#include <libutil/Vec23.hxx> |
4 |
#include <libcoords/Coords.hxx> |
#include <libcoords/Coords.hxx> |
5 |
|
#include <boost/lambda/bind.hpp> |
6 |
|
|
7 |
/** Generic implementation of fillets. |
/** Generic implementation of fillets. |
8 |
*/ |
*/ |
9 |
namespace Fillet { |
namespace Fillet { |
10 |
|
using namespace Vec23; |
11 |
|
using namespace boost::lambda; |
12 |
|
using std::vector; |
13 |
|
|
14 |
PREDBGVAR(dbg); |
PREDBGVAR(dbg); |
15 |
|
|
16 |
struct Vertex { |
/** Transform (currently only linear) an outline. |
17 |
bool sharp; |
*/ |
18 |
bool lineAfter; |
template<class In, class Out> |
19 |
ZPt p; |
void transformOutline(const In &b, const In &e, Out o, |
20 |
|
Coords::CoordSys &coords) { |
21 |
|
transform(b, e, o, |
22 |
|
bind(&Coords::CoordSys::transform, |
23 |
|
&coords, _1)); |
24 |
|
} |
25 |
|
|
26 |
|
/** An implementation of adjacent_find, which takes |
27 |
|
* its predicate as a reference. This makes it easy |
28 |
|
* to do something with the found pair. |
29 |
|
*/ |
30 |
|
template<class In, class Oper> In adjacent_find_operate( |
31 |
|
In begin, In end, Oper &pred) { |
32 |
|
if(begin == end) return end; |
33 |
|
In cur = begin; |
34 |
|
In next = begin; |
35 |
|
while(++next != end) { |
36 |
|
if(pred(*cur, *next)) return cur; |
37 |
|
cur = next; |
38 |
|
} |
39 |
|
return end; |
40 |
} |
} |
41 |
|
|
42 |
/** A generic shape: polylines. |
/** Cut an outline with a given cut function. |
43 |
|
* The outline is simply a range of vertices. |
44 |
|
* The Cut function, when given two vertices should |
45 |
|
* see if it is the point to cut. |
46 |
|
* The member cut should then store the new vertex. |
47 |
|
* <p> |
48 |
|
* The output iterator is filled with |
49 |
|
* the cut point, all vertices of the input range |
50 |
|
* and finally the cut point again. |
51 |
*/ |
*/ |
52 |
class Shape { |
template<class In, class Out, class Cut> |
53 |
vector<Vertex> points; |
bool cutOutline(const In &b, const In &e, |
54 |
|
Out o, Cut &c) { |
55 |
|
In f = adjacent_find_operate(b, e, c); |
56 |
|
if(f == e) { |
57 |
|
In l = e; |
58 |
|
l --; |
59 |
|
if(!c(*l, *b)) return false; |
60 |
|
*o++ = c.cut; |
61 |
|
o = copy(b, e, o); |
62 |
|
*o++ = c.cut; |
63 |
|
return true; |
64 |
|
} |
65 |
|
*o++ = c.cut; |
66 |
|
f++; // point to the middle of the two adjacent. |
67 |
|
o = copy(f, e, o); |
68 |
|
o = copy(b, f, o); |
69 |
|
*o++ = c.cut; |
70 |
|
return true; |
71 |
|
} |
72 |
|
|
73 |
|
inline bool between(float start, float end, float it) { |
74 |
|
return (fabs(start-end) >= fabs(it-end)) && |
75 |
|
(fabs(start-end) >= fabs(it-start)); |
76 |
|
} |
77 |
|
|
78 |
|
struct _Cutter { |
79 |
|
HL iline; |
80 |
|
Pt center; |
81 |
|
Vec fromCenter; |
82 |
|
ZPt cut; |
83 |
|
_Cutter() { } |
84 |
|
bool operator()(const ZPt &a, const ZPt &b) ; |
85 |
|
}; |
86 |
|
|
87 |
|
struct FilletDistort { |
88 |
|
ZPt center; |
89 |
|
ZPt to; |
90 |
|
float width; |
91 |
|
float length; |
92 |
|
Vec dir; |
93 |
|
Vec norm; |
94 |
|
|
95 |
|
FilletDistort(ZPt center, ZPt to, float width) : |
96 |
|
center(center), to(to), width(width) { |
97 |
|
dir = Vec(to-center).normalize(); |
98 |
|
norm = dir.cw90(); |
99 |
|
length = Vec(to-center).length(); |
100 |
|
} |
101 |
|
|
102 |
|
ZPt operator() (ZPt p, bool& wasshifted) ; |
103 |
|
}; |
104 |
|
|
105 |
|
template<class In, class Out, class Shift> |
106 |
|
void shiftEdge(const In &b, |
107 |
|
const In &e, |
108 |
|
Out o, |
109 |
|
Shift &d) { |
110 |
|
In cur = b; |
111 |
|
In prev = b; |
112 |
|
bool prevshifted, curshifted;; |
113 |
|
ZPt prevpt = d(*prev, prevshifted); |
114 |
|
*o++ = prevpt; |
115 |
|
while( (++cur) != e) { |
116 |
|
ZPt curpt = d(*cur, curshifted); |
117 |
|
if(curshifted || prevshifted) { |
118 |
|
// Dice... |
119 |
|
const int n = 30; |
120 |
|
bool fooshifted; |
121 |
|
for(int i=1; i<n; i++) { |
122 |
|
*o++ = d(lerp(*prev, *cur, (float)i / n), fooshifted); |
123 |
|
} |
124 |
|
} |
125 |
|
*o++ = curpt; |
126 |
|
prev = cur; |
127 |
|
prevpt = curpt; |
128 |
|
prevshifted = curshifted; |
129 |
|
} |
130 |
|
} |
131 |
|
|
132 |
|
template<class In, class Out> |
133 |
|
bool blendEdge(const In &b, |
134 |
|
const In &e, |
135 |
|
Out o, |
136 |
|
ZPt center, ZPt to, FilletDistort &d) { |
137 |
|
_Cutter cut; |
138 |
|
cut.iline = HPt(center).line(HPt(to)); |
139 |
|
cut.center = Pt(center); |
140 |
|
cut.fromCenter = Vec(to - center); |
141 |
|
|
142 |
|
vector<ZPt> tmp; |
143 |
|
if(!cutOutline(b, e, back_inserter(tmp), cut)) |
144 |
|
return false; |
145 |
|
|
146 |
|
shiftEdge(tmp.begin(), tmp.end(), o, d); |
147 |
|
return true; |
148 |
|
|
|
public: |
|
|
/** Cut after the vertex i, by inserting two vertices |
|
|
* after it, without a line between them. |
|
|
*/ |
|
|
void cutAfter(int i, float end, float begin); |
|
|
// Shape transform(CoordSys *t, float dicefudge = 1); |
|
149 |
} |
} |
150 |
} |
} |