src/ringFinder.cpp

changeset 1217
314e12e23c3a
parent 985
ed7b31b9f904
child 1222
34def2630300
equal deleted inserted replaced
1216:12f9ea615cbc 1217:314e12e23c3a
23 23
24 RingFinder::RingFinder() {} 24 RingFinder::RingFinder() {}
25 25
26 // ============================================================================= 26 // =============================================================================
27 // 27 //
28 bool RingFinder::findRingsRecursor (double r0, double r1, Solution& currentSolution) 28 bool RingFinder::findRingsRecursor(double r0, double r1, Solution& currentSolution)
29 { 29 {
30 // Don't recurse too deep. 30 // Don't recurse too deep.
31 if (m_stack >= 5 or r1 < r0) 31 if (m_stack >= 5 or r1 < r0)
32 return false; 32 return false;
33 33
34 // Find the scale and number of a ring between r1 and r0. 34 // Find the scale and number of a ring between r1 and r0.
35 double scale = r1 - r0; 35 double scale = r1 - r0;
36 double num = r0 / scale; 36 double num = r0 / scale;
37 37
38 // If the ring number is integral, we have found a fitting ring to r0 -> r1! 38 // If the ring number is integral, we have found a fitting ring to r0 -> r1!
39 if (isInteger (num)) 39 if (isInteger(num))
40 { 40 {
41 Component cmp; 41 Component cmp;
42 cmp.scale = scale; 42 cmp.scale = scale;
43 cmp.num = (int) round (num); 43 cmp.num = (int) round(num);
44 currentSolution.addComponent (cmp); 44 currentSolution.addComponent(cmp);
45 45
46 // If we're still at the first recursion, this is the only 46 // If we're still at the first recursion, this is the only
47 // ring and there's nothing left to do. Guess we found the winner. 47 // ring and there's nothing left to do. Guess we found the winner.
48 if (m_stack == 0) 48 if (m_stack == 0)
49 { 49 {
50 m_solutions.push_back (currentSolution); 50 m_solutions.push_back(currentSolution);
51 return true; 51 return true;
52 } 52 }
53 } 53 }
54 else 54 else
55 { 55 {
56 // Try find solutions by splitting the ring in various positions. 56 // Try find solutions by splitting the ring in various positions.
57 if (isZero (r1 - r0)) 57 if (isZero(r1 - r0))
58 return false; 58 return false;
59 59
60 double interval; 60 double interval;
61 61
62 // Determine interval. The smaller delta between radii, the more precise 62 // Determine interval. The smaller delta between radii, the more precise
75 for (double r = r0 + interval; r < r1; r += interval) 75 for (double r = r0 + interval; r < r1; r += interval)
76 { 76 {
77 Solution sol = currentSolution; 77 Solution sol = currentSolution;
78 78
79 m_stack++; 79 m_stack++;
80 bool res = findRingsRecursor (r0, r, sol) and findRingsRecursor (r, r1, sol); 80 bool res = findRingsRecursor(r0, r, sol) and findRingsRecursor(r, r1, sol);
81 m_stack--; 81 m_stack--;
82 82
83 if (res) 83 if (res)
84 { 84 {
85 // We succeeded in finding radii for this segment. If the stack is 0, this 85 // We succeeded in finding radii for this segment. If the stack is 0, this
88 // 88 //
89 // If not, when this function ends, it will be called again with more arguments. 89 // If not, when this function ends, it will be called again with more arguments.
90 // Accept the solution to this segment by setting currentSolution to sol, and 90 // Accept the solution to this segment by setting currentSolution to sol, and
91 // return true to continue processing. 91 // return true to continue processing.
92 if (m_stack == 0) 92 if (m_stack == 0)
93 m_solutions.push_back (sol); 93 m_solutions.push_back(sol);
94 else 94 else
95 { 95 {
96 currentSolution = sol; 96 currentSolution = sol;
97 return true; 97 return true;
98 } 98 }
105 return true; 105 return true;
106 } 106 }
107 107
108 // 108 //
109 // This is the main algorithm of the ring finder. It tries to use math 109 // This is the main algorithm of the ring finder. It tries to use math
110 // to find the one ring between r0 and r1. If it fails (the ring number 110 // to find the one ring between r0 and r1. If it fails(the ring number
111 // is non-integral), it finds an intermediate radius (ceil of the ring 111 // is non-integral), it finds an intermediate radius(ceil of the ring
112 // number times scale) and splits the radius at this point, calling this 112 // number times scale) and splits the radius at this point, calling this
113 // function again to try find the rings between r0 - r and r - r1. 113 // function again to try find the rings between r0 - r and r - r1.
114 // 114 //
115 // This does not always yield into usable results. If at some point r == 115 // This does not always yield into usable results. If at some point r ==
116 // r0 or r == r1, there is no hope of finding the rings, at least with 116 // r0 or r == r1, there is no hope of finding the rings, at least with
117 // this algorithm, as it would fall into an infinite recursion. 117 // this algorithm, as it would fall into an infinite recursion.
118 // 118 //
119 bool RingFinder::findRings (double r0, double r1) 119 bool RingFinder::findRings(double r0, double r1)
120 { 120 {
121 m_solutions.clear(); 121 m_solutions.clear();
122 Solution sol; 122 Solution sol;
123 123
124 // If we're dealing with fractional radii, try upscale them into integral 124 // If we're dealing with fractional radii, try upscale them into integral
125 // ones. This should yield in more reliable and more optimized results. 125 // ones. This should yield in more reliable and more optimized results.
126 // For instance, using r0=1.5, r1=3.5 causes the algorithm to fail but 126 // For instance, using r0=1.5, r1=3.5 causes the algorithm to fail but
127 // r0=3, r1=7 (scaled up by 2) yields a 2-component solution. We can then 127 // r0=3, r1=7(scaled up by 2) yields a 2-component solution. We can then
128 // downscale the radii back by dividing the scale fields of the solution 128 // downscale the radii back by dividing the scale fields of the solution
129 // components. 129 // components.
130 double scale = 1.0; 130 double scale = 1.0;
131 131
132 if (not isZero (scale = r0 - floor (r0)) or not isZero (scale = r1 - floor (r1))) 132 if (not isZero(scale = r0 - floor(r0)) or not isZero(scale = r1 - floor(r1)))
133 { 133 {
134 double r0f = r0 / scale; 134 double r0f = r0 / scale;
135 double r1f = r1 / scale; 135 double r1f = r1 / scale;
136 136
137 if (isInteger (r0f) and isInteger (r1f)) 137 if (isInteger(r0f) and isInteger(r1f))
138 { 138 {
139 r0 = r0f; 139 r0 = r0f;
140 r1 = r1f; 140 r1 = r1f;
141 } 141 }
142 // If the numbers are both at most one-decimal fractions, we can use a scale of 10 142 // If the numbers are both at most one-decimal fractions, we can use a scale of 10
143 else if (isInteger (r0 * 10) and isInteger (r1 * 10)) 143 else if (isInteger(r0 * 10) and isInteger(r1 * 10))
144 { 144 {
145 scale = 0.1; 145 scale = 0.1;
146 r0 *= 10; 146 r0 *= 10;
147 r1 *= 10; 147 r1 *= 10;
148 } 148 }
151 { 151 {
152 scale = 1.0; 152 scale = 1.0;
153 } 153 }
154 154
155 // Recurse in and try find solutions. 155 // Recurse in and try find solutions.
156 findRingsRecursor (r0, r1, sol); 156 findRingsRecursor(r0, r1, sol);
157 157
158 // If we had upscaled our radii, downscale back now. 158 // If we had upscaled our radii, downscale back now.
159 if (scale != 1.0) 159 if (scale != 1.0)
160 { 160 {
161 for (Solution& sol : m_solutions) 161 for (Solution& sol : m_solutions)
162 sol.scaleComponents (scale); 162 sol.scaleComponents(scale);
163 } 163 }
164 164
165 // Compare the solutions and find the best one. The solution class has an operator> 165 // Compare the solutions and find the best one. The solution class has an operator>
166 // overload to compare two solutions. 166 // overload to compare two solutions.
167 m_bestSolution = nullptr; 167 m_bestSolution = nullptr;
168 168
169 for (Solution const& sol : m_solutions) 169 for (Solution const& sol : m_solutions)
170 { 170 {
171 if (m_bestSolution == nullptr or sol.isSuperiorTo (m_bestSolution)) 171 if (m_bestSolution == nullptr or sol.isSuperiorTo(m_bestSolution))
172 m_bestSolution = &sol; 172 m_bestSolution = &sol;
173 } 173 }
174 174
175 return (m_bestSolution); 175 return (m_bestSolution);
176 } 176 }
186 // yield less new primitives and cleaner definitions. 186 // yield less new primitives and cleaner definitions.
187 // 187 //
188 // The solution which is found superior to every other solution 188 // The solution which is found superior to every other solution
189 // will be the one returned by RingFinder::bestSolution(). 189 // will be the one returned by RingFinder::bestSolution().
190 // 190 //
191 bool RingFinder::Solution::isSuperiorTo (const Solution* other) const 191 bool RingFinder::Solution::isSuperiorTo(const Solution* other) const
192 { 192 {
193 // If one solution has less components than the other one, it is definitely 193 // If one solution has less components than the other one, it is definitely
194 // better. 194 // better.
195 if (getComponents().size() != other->getComponents().size()) 195 if (getComponents().size() != other->getComponents().size())
196 return getComponents().size() < other->getComponents().size(); 196 return getComponents().size() < other->getComponents().size();
201 int maxA = 0, 201 int maxA = 0,
202 maxB = 0; 202 maxB = 0;
203 203
204 for (int i = 0; i < getComponents().size(); ++i) 204 for (int i = 0; i < getComponents().size(); ++i)
205 { 205 {
206 maxA = qMax (getComponents()[i].num, maxA); 206 maxA = qMax(getComponents()[i].num, maxA);
207 maxB = qMax (other->getComponents()[i].num, maxB); 207 maxB = qMax(other->getComponents()[i].num, maxB);
208 } 208 }
209 209
210 if (maxA != maxB) 210 if (maxA != maxB)
211 return maxA < maxB; 211 return maxA < maxB;
212 212
214 // just say this one is better, at this point it does not matter which 214 // just say this one is better, at this point it does not matter which
215 // one is chosen. 215 // one is chosen.
216 return true; 216 return true;
217 } 217 }
218 218
219 void RingFinder::Solution::scaleComponents (double scale) 219 void RingFinder::Solution::scaleComponents(double scale)
220 { 220 {
221 for (Component& cmp : m_components) 221 for (Component& cmp : m_components)
222 cmp.scale *= scale; 222 cmp.scale *= scale;
223 } 223 }

mercurial