src/misc.cpp

changeset 507
fc76d38c3530
parent 504
6a1fa662bfc1
child 508
7ace3537a560
equal deleted inserted replaced
506:525f6c48db83 507:fc76d38c3530
313 // 313 //
314 // This does not always yield into usable results. If at some point r == r0 or 314 // This does not always yield into usable results. If at some point r == r0 or
315 // r == r1, there is no hope of finding the rings, at least with this algorithm, 315 // r == r1, there is no hope of finding the rings, at least with this algorithm,
316 // as it would fall into an infinite recursion. 316 // as it would fall into an infinite recursion.
317 // ----------------------------------------------------------------------------- 317 // -----------------------------------------------------------------------------
318 bool RingFinder::findRings (double r0, double r1) 318 bool RingFinder::findRingsRecursor (double r0, double r1, Solution& currentSolution)
319 { m_solution.clear(); 319 { char tabs[64];
320 return findRingsRecursor (r0, r1); 320 memset (tabs, '\t', m_stack);
321 } 321 tabs[m_stack] = '\0';
322 322
323 bool RingFinder::findRingsRecursor (double r0, double r1) 323 // Don't recurse too deep.
324 { // Find the scale and number of a ring between r1 and r0. 324 if (m_stack >= 5)
325 return false;
326
327 // Find the scale and number of a ring between r1 and r0.
328 assert (r1 >= r0);
325 double scale = r1 - r0; 329 double scale = r1 - r0;
326 double num = r0 / scale; 330 double num = r0 / scale;
327 331
328 // If the ring number is integral, we have found a fitting ring to r0 -> r1! 332 // If the ring number is integral, we have found a fitting ring to r0 -> r1!
329 if (isInteger (num)) 333 if (isInteger (num))
330 { SolutionComponent cmp; 334 { Component cmp;
331 cmp.scale = scale; 335 cmp.scale = scale;
332 cmp.num = (int) ceil (num); 336 cmp.num = (int) round (num);
333 m_solution << cmp; 337 currentSolution.addComponent (cmp);
338
339 // If we're still at the first recursion, this is the only
340 // ring and there's nothing left to do. Guess we found the winner.
341 if (m_stack == 0)
342 { m_solutions.push_back (currentSolution);
343 return true;
344 }
334 } 345 }
335 else 346 else
336 { // If not, find an intermediate <r> between the radii 347 { // Try find solutions by splitting the ring in various positions.
337 double r = ceil (num) * scale; 348 if (isZero (r1 - r0))
338
339 // If r is the same as r0 or r1, we simply cannot find any rings between
340 // r0 and r1. Stop and return failure.
341 if (isZero (r0 - r) || isZero (r1 - r))
342 return false; 349 return false;
343 350
344 // Split this ring into r0 -> r and r -> r1. Recurse to possibly find 351 double interval;
345 // the rings for these. If either recurse fails, the entire algorithm 352
346 // fails as well. 353 // Determine interval. The smaller delta between radii, the more precise
347 if (!findRingsRecursor (r0, r) || !findRingsRecursor (r, r1)) 354 // interval should be used. We can't really use a 0.5 increment when
348 return false; 355 // calculating rings to 10 -> 105... that would take ages to process!
349 } 356 if (r1 - r0 < 0.5)
350 357 interval = 0.1;
351 // The algorithm did not fail, thus we succeeded! 358 else if (r1 - r0 < 10)
359 interval = 0.5;
360 else if (r1 - r0 < 50)
361 interval = 1;
362 else
363 interval = 5;
364
365 // Now go through possible splits and try find rings for both segments.
366 for (double r = r0 + interval; r < r1; r += interval)
367 { Solution sol = currentSolution;
368
369 m_stack++;
370 bool res = findRingsRecursor (r0, r, sol) && findRingsRecursor (r, r1, sol);
371 m_stack--;
372
373 if (res)
374 { // We succeeded in finding radii for this segment. If the stack is 0, this
375 // is the first recursion to this function. Thus there are no more ring segments
376 // to process and we can add the solution.
377 //
378 // If not, when this function ends, it will be called again with more arguments.
379 // Accept the solution to this segment by setting currentSolution to sol, and
380 // return true to continue processing.
381 if (m_stack == 0)
382 m_solutions.push_back (sol);
383 else
384 { currentSolution = sol;
385 return true;
386 }
387 }
388 }
389
390 return false;
391 }
392
352 return true; 393 return true;
353 } 394 }
395
396 // =============================================================================
397 // Main function. Call this with r0 and r1. If this returns true, use bestSolution
398 // for the solution that was presented.
399 // -----------------------------------------------------------------------------
400 bool RingFinder::findRings (double r0, double r1)
401 { m_solutions.clear();
402 Solution sol;
403
404 // Recurse in and try find solutions.
405 findRingsRecursor (r0, r1, sol);
406
407 // Compare the solutions and find the best one. The solution class has an operator>
408 // overload to compare two solutions.
409 m_bestSolution = null;
410
411 for (QVector<Solution>::iterator solp = m_solutions.begin(); solp != m_solutions.end(); ++solp)
412 { const Solution& sol = *solp;
413
414 if (m_bestSolution == null || sol > *m_bestSolution)
415 m_bestSolution = &sol;
416 }
417
418 return (m_bestSolution != null);
419 }
420
421 // =============================================================================
422 // -----------------------------------------------------------------------------
423 bool RingFinder::Solution::operator> (const RingFinder::Solution& other) const
424 { // If this solution has less components than the other one, this one
425 // is definitely better.
426 if (components().size() < other.components().size())
427 return true;
428
429 // vice versa
430 if (other.components().size() < components().size())
431 return false;
432
433 // Calculate the maximum ring number. Since the solutions have equal
434 // ring counts, the solutions with lesser maximum rings should result
435 // in cleaner code and less new primitives, right?
436 int maxA = 0,
437 maxB = 0;
438
439 for (int i = 0; i < components().size(); ++i)
440 { if (components()[i].num > maxA)
441 maxA = components()[i].num;
442
443 if (other.components()[i].num > maxB)
444 maxB = other.components()[i].num;
445 }
446
447 if (maxA < maxB)
448 return true;
449
450 if (maxB < maxA)
451 return false;
452
453 // Solutions have equal rings and equal maximum ring numbers. Let's
454 // just say this one is better, at this point it does not matter which
455 // one is chosen.
456 return true;
457 }

mercurial