dechunk.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. from __future__ import annotations
  2. from typing import TYPE_CHECKING, cast
  3. from contourpy._contourpy import FillType, LineType
  4. from contourpy.array import (
  5. concat_codes_or_none, concat_offsets_or_none, concat_points_or_none,
  6. concat_points_or_none_with_nan,
  7. )
  8. from contourpy.enum_util import as_fill_type, as_line_type
  9. from contourpy.typecheck import check_filled, check_lines
  10. if TYPE_CHECKING:
  11. import contourpy._contourpy as cpy
  12. def dechunk_filled(filled: cpy.FillReturn, fill_type: FillType | str) -> cpy.FillReturn:
  13. """Return the specified filled contours with all chunked data moved into the first chunk.
  14. Filled contours that are not chunked (``FillType.OuterCode`` and ``FillType.OuterOffset``) and
  15. those that are but only contain a single chunk are returned unmodified. Individual polygons are
  16. unchanged, they are not geometrically combined.
  17. Args:
  18. filled (sequence of arrays): Filled contour data as returned by
  19. :func:`~contourpy.ContourGenerator.filled`.
  20. fill_type (FillType or str): Type of ``filled`` as enum or string equivalent.
  21. Return:
  22. Filled contours in a single chunk.
  23. .. versionadded:: 1.2.0
  24. """
  25. fill_type = as_fill_type(fill_type)
  26. if fill_type in (FillType.OuterCode, FillType.OuterOffset):
  27. # No-op if fill_type is not chunked.
  28. return filled
  29. check_filled(filled, fill_type)
  30. if len(filled[0]) < 2:
  31. # No-op if just one chunk.
  32. return filled
  33. if TYPE_CHECKING:
  34. filled = cast(cpy.FillReturn_Chunk, filled)
  35. points = concat_points_or_none(filled[0])
  36. if fill_type == FillType.ChunkCombinedCode:
  37. if TYPE_CHECKING:
  38. filled = cast(cpy.FillReturn_ChunkCombinedCode, filled)
  39. if points is None:
  40. ret1: cpy.FillReturn_ChunkCombinedCode = ([None], [None])
  41. else:
  42. ret1 = ([points], [concat_codes_or_none(filled[1])])
  43. return ret1
  44. elif fill_type == FillType.ChunkCombinedOffset:
  45. if TYPE_CHECKING:
  46. filled = cast(cpy.FillReturn_ChunkCombinedOffset, filled)
  47. if points is None:
  48. ret2: cpy.FillReturn_ChunkCombinedOffset = ([None], [None])
  49. else:
  50. ret2 = ([points], [concat_offsets_or_none(filled[1])])
  51. return ret2
  52. elif fill_type == FillType.ChunkCombinedCodeOffset:
  53. if TYPE_CHECKING:
  54. filled = cast(cpy.FillReturn_ChunkCombinedCodeOffset, filled)
  55. if points is None:
  56. ret3: cpy.FillReturn_ChunkCombinedCodeOffset = ([None], [None], [None])
  57. else:
  58. outer_offsets = concat_offsets_or_none(filled[2])
  59. ret3 = ([points], [concat_codes_or_none(filled[1])], [outer_offsets])
  60. return ret3
  61. elif fill_type == FillType.ChunkCombinedOffsetOffset:
  62. if TYPE_CHECKING:
  63. filled = cast(cpy.FillReturn_ChunkCombinedOffsetOffset, filled)
  64. if points is None:
  65. ret4: cpy.FillReturn_ChunkCombinedOffsetOffset = ([None], [None], [None])
  66. else:
  67. outer_offsets = concat_offsets_or_none(filled[2])
  68. ret4 = ([points], [concat_offsets_or_none(filled[1])], [outer_offsets])
  69. return ret4
  70. else:
  71. raise ValueError(f"Invalid FillType {fill_type}")
  72. def dechunk_lines(lines: cpy.LineReturn, line_type: LineType | str) -> cpy.LineReturn:
  73. """Return the specified contour lines with all chunked data moved into the first chunk.
  74. Contour lines that are not chunked (``LineType.Separate`` and ``LineType.SeparateCode``) and
  75. those that are but only contain a single chunk are returned unmodified. Individual lines are
  76. unchanged, they are not geometrically combined.
  77. Args:
  78. lines (sequence of arrays): Contour line data as returned by
  79. :func:`~contourpy.ContourGenerator.lines`.
  80. line_type (LineType or str): Type of ``lines`` as enum or string equivalent.
  81. Return:
  82. Contour lines in a single chunk.
  83. .. versionadded:: 1.2.0
  84. """
  85. line_type = as_line_type(line_type)
  86. if line_type in (LineType.Separate, LineType.SeparateCode):
  87. # No-op if line_type is not chunked.
  88. return lines
  89. check_lines(lines, line_type)
  90. if len(lines[0]) < 2:
  91. # No-op if just one chunk.
  92. return lines
  93. if TYPE_CHECKING:
  94. lines = cast(cpy.LineReturn_Chunk, lines)
  95. if line_type == LineType.ChunkCombinedCode:
  96. if TYPE_CHECKING:
  97. lines = cast(cpy.LineReturn_ChunkCombinedCode, lines)
  98. points = concat_points_or_none(lines[0])
  99. if points is None:
  100. ret1: cpy.LineReturn_ChunkCombinedCode = ([None], [None])
  101. else:
  102. ret1 = ([points], [concat_codes_or_none(lines[1])])
  103. return ret1
  104. elif line_type == LineType.ChunkCombinedOffset:
  105. if TYPE_CHECKING:
  106. lines = cast(cpy.LineReturn_ChunkCombinedOffset, lines)
  107. points = concat_points_or_none(lines[0])
  108. if points is None:
  109. ret2: cpy.LineReturn_ChunkCombinedOffset = ([None], [None])
  110. else:
  111. ret2 = ([points], [concat_offsets_or_none(lines[1])])
  112. return ret2
  113. elif line_type == LineType.ChunkCombinedNan:
  114. if TYPE_CHECKING:
  115. lines = cast(cpy.LineReturn_ChunkCombinedNan, lines)
  116. points = concat_points_or_none_with_nan(lines[0])
  117. ret3: cpy.LineReturn_ChunkCombinedNan = ([points],)
  118. return ret3
  119. else:
  120. raise ValueError(f"Invalid LineType {line_type}")