// Return a copy of this. If good_only will only copy the Good ColPartitions.
ColPartitionSet* ColPartitionSet::Copy(bool good_only) {
  ColPartition_LIST copy_parts;
  ColPartition_IT src_it(&parts_);
  ColPartition_IT dest_it(&copy_parts);
  for (src_it.mark_cycle_pt(); !src_it.cycled_list(); src_it.forward()) {
    ColPartition* part = src_it.data();
    if (BLOBNBOX::IsTextType(part->blob_type()) &&
        (!good_only || part->good_width() || part->good_column()))
      dest_it.add_after_then_move(part->ShallowCopy());
  }
  if (dest_it.empty())
    return NULL;
  return new ColPartitionSet(&copy_parts);
}
// Static helper for C_BLOB::rotate to allow recursion of child outlines.
void RotateOutlineList(const FCOORD& rotation, C_OUTLINE_LIST* outlines) {
  C_OUTLINE_LIST new_outlines;
  C_OUTLINE_IT src_it(outlines);
  C_OUTLINE_IT dest_it(&new_outlines);
  while (!src_it.empty()) {
    C_OUTLINE* old_outline = src_it.extract();
    src_it.forward();
    C_OUTLINE* new_outline = new C_OUTLINE(old_outline, rotation);
    if (!old_outline->child()->empty()) {
      RotateOutlineList(rotation, old_outline->child());
      C_OUTLINE_IT child_it(new_outline->child());
      child_it.add_list_after(old_outline->child());
    }
    delete old_outline;
    dest_it.add_to_end(new_outline);
  }
  src_it.add_list_after(&new_outlines);
}
// The column_set has changed. Close down all in-progress WorkingPartSets in
// columns that do not match and start new ones for the new columns in this.
// As ColPartitions are turned into BLOCKs, the used ones are put in
// used_parts, as they still need to be referenced in the grid.
void ColPartitionSet::ChangeWorkColumns(const ICOORD& bleft,
                                        const ICOORD& tright,
                                        int resolution,
                                        ColPartition_LIST* used_parts,
                                        WorkingPartSet_LIST* working_set_list) {
  // Move the input list to a temporary location so we can delete its elements
  // as we add them to the output working_set.
  WorkingPartSet_LIST work_src;
  WorkingPartSet_IT src_it(&work_src);
  src_it.add_list_after(working_set_list);
  src_it.move_to_first();
  WorkingPartSet_IT dest_it(working_set_list);
  // Completed blocks and to_blocks are accumulated and given to the first new
  // one  whenever we keep a column, or at the end.
  BLOCK_LIST completed_blocks;
  TO_BLOCK_LIST to_blocks;
  WorkingPartSet* first_new_set = NULL;
  WorkingPartSet* working_set = NULL;
  ColPartition_IT col_it(&parts_);
  for (col_it.mark_cycle_pt(); !col_it.cycled_list(); col_it.forward()) {
    ColPartition* column = col_it.data();
    // Any existing column to the left of column is completed.
    while (!src_it.empty() &&
           ((working_set = src_it.data())->column() == NULL ||
            working_set->column()->right_key() <= column->left_key())) {
      src_it.extract();
      working_set->ExtractCompletedBlocks(bleft, tright, resolution,
                                          used_parts, &completed_blocks,
                                          &to_blocks);
      delete working_set;
      src_it.forward();
    }
    // Make a new between-column WorkingSet for before the current column.
    working_set = new WorkingPartSet(NULL);
    dest_it.add_after_then_move(working_set);
    if (first_new_set == NULL)
      first_new_set = working_set;
    // A matching column gets to stay, and first_new_set gets all the
    // completed_sets.
    working_set = src_it.empty() ? NULL : src_it.data();
    if (working_set != NULL &&
        working_set->column()->MatchingColumns(*column)) {
      working_set->set_column(column);
      dest_it.add_after_then_move(src_it.extract());
      src_it.forward();
      first_new_set->InsertCompletedBlocks(&completed_blocks, &to_blocks);
      first_new_set = NULL;
    } else {
      // Just make a new working set for the current column.
      working_set = new WorkingPartSet(column);
      dest_it.add_after_then_move(working_set);
    }
  }
  // Complete any remaining src working sets.
  while (!src_it.empty()) {
    working_set = src_it.extract();
    working_set->ExtractCompletedBlocks(bleft, tright, resolution,
                                        used_parts, &completed_blocks,
                                        &to_blocks);
    delete working_set;
    src_it.forward();
  }
  // Make a new between-column WorkingSet for after the last column.
  working_set = new WorkingPartSet(NULL);
  dest_it.add_after_then_move(working_set);
  if (first_new_set == NULL)
    first_new_set = working_set;
  // The first_new_set now gets any accumulated completed_parts/blocks.
  first_new_set->InsertCompletedBlocks(&completed_blocks, &to_blocks);
}