serial.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #include "base_impl.h"
  2. #include "converter.h"
  3. #include "serial.h"
  4. namespace contourpy {
  5. SerialContourGenerator::SerialContourGenerator(
  6. const CoordinateArray& x, const CoordinateArray& y, const CoordinateArray& z,
  7. const MaskArray& mask, bool corner_mask, LineType line_type, FillType fill_type,
  8. bool quad_as_tri, ZInterp z_interp, index_t x_chunk_size, index_t y_chunk_size)
  9. : BaseContourGenerator(x, y, z, mask, corner_mask, line_type, fill_type, quad_as_tri, z_interp,
  10. x_chunk_size, y_chunk_size)
  11. {}
  12. void SerialContourGenerator::export_filled(
  13. const ChunkLocal& local, std::vector<py::list>& return_lists)
  14. {
  15. assert(local.total_point_count > 0);
  16. switch (get_fill_type())
  17. {
  18. case FillType::OuterCode:
  19. case FillType::OuterOffset: {
  20. assert(!has_direct_points() && !has_direct_line_offsets());
  21. auto outer_count = local.line_count - local.hole_count;
  22. for (decltype(outer_count) i = 0; i < outer_count; ++i) {
  23. auto outer_start = local.outer_offsets.start[i];
  24. auto outer_end = local.outer_offsets.start[i+1];
  25. auto point_start = local.line_offsets.start[outer_start];
  26. auto point_end = local.line_offsets.start[outer_end];
  27. auto point_count = point_end - point_start;
  28. assert(point_count > 2);
  29. return_lists[0].append(Converter::convert_points(
  30. point_count, local.points.start + 2*point_start));
  31. if (get_fill_type() == FillType::OuterCode)
  32. return_lists[1].append(Converter::convert_codes(
  33. point_count, outer_end - outer_start + 1,
  34. local.line_offsets.start + outer_start, point_start));
  35. else
  36. return_lists[1].append(Converter::convert_offsets(
  37. outer_end - outer_start + 1, local.line_offsets.start + outer_start,
  38. point_start));
  39. }
  40. break;
  41. }
  42. case FillType::ChunkCombinedCode:
  43. case FillType::ChunkCombinedCodeOffset: {
  44. assert(has_direct_points() && !has_direct_line_offsets());
  45. // return_lists[0][local_chunk] already contains combined points.
  46. // If ChunkCombinedCodeOffset. return_lists[2][local.chunk] already contains outer
  47. // offsets.
  48. return_lists[1][local.chunk] = Converter::convert_codes(
  49. local.total_point_count, local.line_count + 1, local.line_offsets.start, 0);
  50. break;
  51. }
  52. case FillType::ChunkCombinedOffset:
  53. case FillType::ChunkCombinedOffsetOffset:
  54. assert(has_direct_points() && has_direct_line_offsets());
  55. if (get_fill_type() == FillType::ChunkCombinedOffsetOffset) {
  56. assert(has_direct_outer_offsets());
  57. }
  58. // return_lists[0][local_chunk] already contains combined points.
  59. // return_lists[1][local.chunk] already contains line offsets.
  60. // If ChunkCombinedOffsetOffset, return_lists[2][local.chunk] already contains
  61. // outer offsets.
  62. break;
  63. }
  64. }
  65. void SerialContourGenerator::export_lines(
  66. const ChunkLocal& local, std::vector<py::list>& return_lists)
  67. {
  68. assert(local.total_point_count > 0);
  69. switch (get_line_type())
  70. {
  71. case LineType::Separate:
  72. case LineType::SeparateCode: {
  73. assert(!has_direct_points() && !has_direct_line_offsets());
  74. bool separate_code = (get_line_type() == LineType::SeparateCode);
  75. for (decltype(local.line_count) i = 0; i < local.line_count; ++i) {
  76. auto point_start = local.line_offsets.start[i];
  77. auto point_end = local.line_offsets.start[i+1];
  78. auto point_count = point_end - point_start;
  79. assert(point_count > 1);
  80. return_lists[0].append(Converter::convert_points(
  81. point_count, local.points.start + 2*point_start));
  82. if (separate_code) {
  83. return_lists[1].append(
  84. Converter::convert_codes_check_closed_single(
  85. point_count, local.points.start + 2*point_start));
  86. }
  87. }
  88. break;
  89. }
  90. case LineType::ChunkCombinedCode: {
  91. assert(has_direct_points() && !has_direct_line_offsets());
  92. // return_lists[0][local.chunk] already contains points.
  93. return_lists[1][local.chunk] = Converter::convert_codes_check_closed(
  94. local.total_point_count, local.line_count + 1, local.line_offsets.start,
  95. local.points.start);
  96. break;
  97. }
  98. case LineType::ChunkCombinedOffset:
  99. assert(has_direct_points() && has_direct_line_offsets());
  100. // return_lists[0][local.chunk] already contains points.
  101. // return_lists[1][local.chunk] already contains line offsets.
  102. break;
  103. case LineType::ChunkCombinedNan:
  104. assert(has_direct_points());
  105. // return_lists[0][local.chunk] already contains points.
  106. break;
  107. }
  108. }
  109. void SerialContourGenerator::march(std::vector<py::list>& return_lists)
  110. {
  111. auto n_chunks = get_n_chunks();
  112. bool single_chunk = (n_chunks == 1);
  113. if (single_chunk) {
  114. // Stage 1: If single chunk, initialise cache z-levels and starting locations for whole
  115. // domain.
  116. init_cache_levels_and_starts();
  117. }
  118. // Stage 2: Trace contours.
  119. ChunkLocal local;
  120. for (index_t chunk = 0; chunk < n_chunks; ++chunk) {
  121. get_chunk_limits(chunk, local);
  122. if (!single_chunk)
  123. init_cache_levels_and_starts(&local);
  124. march_chunk(local, return_lists);
  125. local.clear();
  126. }
  127. }
  128. } // namespace contourpy