morphing.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * morphing.cpp - path morphing
  3. * Copyright (C) 2017 caryoscelus
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <morphing/morphing.h>
  19. #include <geom_helpers/knots.h>
  20. #include <geom_helpers/split.h>
  21. #include <set>
  22. #include <experimental/numeric>
  23. namespace morphing {
  24. using Geom::Knot;
  25. using Geom::BezierKnots;
  26. Knot knot_average(Knot const& a, Knot const& b, double amount) {
  27. auto a_amount = 1.0-amount;
  28. return Knot(a.pos*a_amount + b.pos*amount,
  29. a.tg1*a_amount + b.tg1*amount,
  30. a.tg2*a_amount + b.tg2*amount);
  31. }
  32. BezierKnots simple_average(BezierKnots const& a, BezierKnots const& b, double amount) {
  33. if (a.closed != b.closed)
  34. throw MorphingError("a nd b have different closedness");
  35. if (a.knots.size() != b.knots.size())
  36. throw MorphingError("a and b have different length");
  37. BezierKnots result;
  38. for (size_t i = 0; i < a.knots.size(); ++i) {
  39. result.knots.push_back(knot_average(a.knots[i], b.knots[i], amount));
  40. }
  41. return result;
  42. }
  43. using MorphingKeys = std::vector<std::pair<Knot::Id, size_t>>;
  44. void read_keys(BezierKnots const& src, MorphingKeys& keys, std::set<Knot::Id>& keyset) {
  45. size_t index = 0;
  46. for (auto const& knot : src.knots) {
  47. if (!knot.uid.empty()) {
  48. keys.emplace_back(knot.uid, index);
  49. keyset.insert(knot.uid);
  50. }
  51. ++index;
  52. }
  53. }
  54. void intersect_keys(BezierKnots const& a, BezierKnots const& b, MorphingKeys& keys_a, MorphingKeys& keys_b) {
  55. MorphingKeys all_a, all_b;
  56. std::set<Knot::Id> set_a, set_b;
  57. read_keys(a, all_a, set_a);
  58. read_keys(b, all_b, set_b);
  59. auto filter = [&set_a, &set_b](auto pair) {
  60. return
  61. set_a.find(pair.first) != std::end(set_a) &&
  62. set_b.find(pair.first) != std::end(set_b);
  63. };
  64. std::copy_if(
  65. std::begin(all_a), std::end(all_a),
  66. std::back_inserter(keys_a),
  67. filter
  68. );
  69. std::copy_if(
  70. std::begin(all_b), std::end(all_b),
  71. std::back_inserter(keys_b),
  72. filter
  73. );
  74. }
  75. template<typename I>
  76. std::vector<I> get_indexes(I prev, I curr, I amount) {
  77. std::vector<I> result;
  78. if (prev < curr) {
  79. for (auto i = prev+1; i <= curr; ++i)
  80. result.push_back(i);
  81. } else {
  82. for (auto i = prev+1; i < amount; ++i)
  83. result.push_back(i);
  84. for (size_t i = 0; i <= curr; ++i)
  85. result.push_back(i);
  86. }
  87. return result;
  88. }
  89. void calculate_split(std::vector<Geom::PathTime>& result, std::vector<size_t> indexes, unsigned split) {
  90. std::cerr << "calculate split " << split << std::endl;
  91. for (auto index : indexes) {
  92. for (unsigned i = 1; i < split; ++i) {
  93. result.push_back(index + 1.0*i/split);
  94. }
  95. }
  96. }
  97. void prepare_average(BezierKnots const& a, BezierKnots const& b, BezierKnots& target_a, BezierKnots& target_b) {
  98. // collect keys
  99. // intersect keys
  100. MorphingKeys keys_a;
  101. MorphingKeys keys_b;
  102. intersect_keys(a, b, keys_a, keys_b);
  103. if (keys_a.size() != keys_b.size())
  104. throw MorphingError("Different size");
  105. if (keys_a.empty())
  106. throw MorphingError("No common keys");
  107. // for each interval: calculate split
  108. std::vector<Geom::PathTime> div_a;
  109. std::vector<Geom::PathTime> div_b;
  110. auto prev_a = keys_a.rbegin()->second;
  111. auto prev_b = keys_b.rbegin()->second;
  112. auto key_a = std::begin(keys_a);
  113. auto key_b = std::begin(keys_b);
  114. for (; key_a != std::end(keys_a); ++key_a, ++key_b) {
  115. std::cerr << key_a->first << ", " << prev_a << std::endl;
  116. std::vector<size_t> indexes_a = get_indexes(prev_a, key_a->second, a.size());
  117. std::vector<size_t> indexes_b = get_indexes(prev_b, key_b->second, b.size());
  118. auto a_size = indexes_a.size();
  119. auto b_size = indexes_b.size();
  120. if (a_size == b_size) {
  121. // 1 : 1 - trivial case - do nothing
  122. } else if (a_size % b_size == 0) {
  123. // k : 1 - only split b
  124. calculate_split(div_b, indexes_b, a_size/b_size);
  125. } else if (b_size % a_size == 0) {
  126. // 1 : k - only split a
  127. calculate_split(div_a, indexes_a, b_size/a_size);
  128. } else {
  129. auto lcm = std::experimental::lcm(a_size, b_size);
  130. calculate_split(div_a, indexes_a, lcm/a_size);
  131. calculate_split(div_b, indexes_b, lcm/b_size);
  132. }
  133. prev_a = key_a->second;
  134. prev_b = key_b->second;
  135. }
  136. // apply split
  137. auto path_a = Geom::knots_to_path(a);
  138. auto path_b = Geom::knots_to_path(b);
  139. if (div_a.size() > 0) {
  140. target_a = Geom::path_to_knots(Geom::split_and_merge_path(path_a, div_a));
  141. target_a.closed = a.closed;
  142. } else {
  143. target_a = a;
  144. }
  145. if (div_b.size() > 0) {
  146. target_b = Geom::path_to_knots(Geom::split_and_merge_path(path_b, div_b));
  147. target_b.closed = b.closed;
  148. } else {
  149. target_b = b;
  150. }
  151. }
  152. BezierKnots average(BezierKnots const& from, BezierKnots const& to, double amount) {
  153. BezierKnots from_f, to_f;
  154. prepare_average(from, to, from_f, to_f);
  155. return simple_average(from_f, to_f, amount);
  156. }
  157. } // namespace morphing