#include "base_impl.h"
#include "converter.h"
#include "serial.h"
namespace contourpy {
SerialContourGenerator::SerialContourGenerator(
const CoordinateArray& x, const CoordinateArray& y, const CoordinateArray& z,
const MaskArray& mask, bool corner_mask, LineType line_type, FillType fill_type,
bool quad_as_tri, ZInterp z_interp, index_t x_chunk_size, index_t y_chunk_size)
: BaseContourGenerator(x, y, z, mask, corner_mask, line_type, fill_type, quad_as_tri, z_interp,
x_chunk_size, y_chunk_size)
{}
void SerialContourGenerator::export_filled(
const ChunkLocal& local, std::vector<py::list>& return_lists)
{
assert(local.total_point_count > 0);
switch (get_fill_type())
{
case FillType::OuterCode:
case FillType::OuterOffset: {
assert(!has_direct_points() && !has_direct_line_offsets());
auto outer_count = local.line_count - local.hole_count;
for (decltype(outer_count) i = 0; i < outer_count; ++i) {
auto outer_start = local.outer_offsets.start[i];
auto outer_end = local.outer_offsets.start[i+1];
auto point_start = local.line_offsets.start[outer_start];
auto point_end = local.line_offsets.start[outer_end];
auto point_count = point_end - point_start;
assert(point_count > 2);
return_lists[0].append(Converter::convert_points(
point_count, local.points.start + 2*point_start));
if (get_fill_type() == FillType::OuterCode)
return_lists[1].append(Converter::convert_codes(
point_count, outer_end - outer_start + 1,
local.line_offsets.start + outer_start, point_start));
else
return_lists[1].append(Converter::convert_offsets(
outer_end - outer_start + 1, local.line_offsets.start + outer_start,
point_start));
}
break;
}
case FillType::ChunkCombinedCode:
case FillType::ChunkCombinedCodeOffset: {
assert(has_direct_points() && !has_direct_line_offsets());
// return_lists[0][local_chunk] already contains combined points.
// If ChunkCombinedCodeOffset. return_lists[2][local.chunk] already contains outer
// offsets.
return_lists[1][local.chunk] = Converter::convert_codes(
local.total_point_count, local.line_count + 1, local.line_offsets.start, 0);
break;
}
case FillType::ChunkCombinedOffset:
case FillType::ChunkCombinedOffsetOffset:
assert(has_direct_points() && has_direct_line_offsets());
if (get_fill_type() == FillType::ChunkCombinedOffsetOffset) {
assert(has_direct_outer_offsets());
}
// return_lists[0][local_chunk] already contains combined points.
// return_lists[1][local.chunk] already contains line offsets.
// If ChunkCombinedOffsetOffset, return_lists[2][local.chunk] already contains
// outer offsets.
break;
}
}
void SerialContourGenerator::export_lines(
const ChunkLocal& local, std::vector<py::list>& return_lists)
{
assert(local.total_point_count > 0);
switch (get_line_type())
{
case LineType::Separate:
case LineType::SeparateCode: {
assert(!has_direct_points() && !has_direct_line_offsets());
bool separate_code = (get_line_type() == LineType::SeparateCode);
for (decltype(local.line_count) i = 0; i < local.line_count; ++i) {
auto point_start = local.line_offsets.start[i];
auto point_end = local.line_offsets.start[i+1];
auto point_count = point_end - point_start;
assert(point_count > 1);
return_lists[0].append(Converter::convert_points(
point_count, local.points.start + 2*point_start));
if (separate_code) {
return_lists[1].append(
Converter::convert_codes_check_closed_single(
point_count, local.points.start + 2*point_start));
}
}
break;
}
case LineType::ChunkCombinedCode: {
assert(has_direct_points() && !has_direct_line_offsets());
// return_lists[0][local.chunk] already contains points.
return_lists[1][local.chunk] = Converter::convert_codes_check_closed(
local.total_point_count, local.line_count + 1, local.line_offsets.start,
local.points.start);
break;
}
case LineType::ChunkCombinedOffset:
assert(has_direct_points() && has_direct_line_offsets());
// return_lists[0][local.chunk] already contains points.
// return_lists[1][local.chunk] already contains line offsets.
break;
case LineType::ChunkCombinedNan:
assert(has_direct_points());
// return_lists[0][local.chunk] already contains points.
break;
}
}
void SerialContourGenerator::march(std::vector<py::list>& return_lists)
{
auto n_chunks = get_n_chunks();
bool single_chunk = (n_chunks == 1);
if (single_chunk) {
// Stage 1: If single chunk, initialise cache z-levels and starting locations for whole
// domain.
init_cache_levels_and_starts();
}
// Stage 2: Trace contours.
ChunkLocal local;
for (index_t chunk = 0; chunk < n_chunks; ++chunk) {
get_chunk_limits(chunk, local);
if (!single_chunk)
init_cache_levels_and_starts(&local);
march_chunk(local, return_lists);
local.clear();
}
}
} // namespace contourpy