Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/levelselection.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzTools includes
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tfilepath.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tregion.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Boost includes
Toshihiro Shimizu 890ddd
#include <boost algorithm="" copy_if.hpp="" cxx11=""></boost>
Toshihiro Shimizu 890ddd
#include <boost counting_iterator.hpp="" iterator=""></boost>
Toshihiro Shimizu 890ddd
#include <boost bind.hpp=""></boost>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace boost_a = boost::algorithm;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*******************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace  stuff
Toshihiro Shimizu 890ddd
//*******************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TTool *tool() { return TTool::getApplication()->getCurrentTool()->getTool(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct StrokeData {
Shinya Kitaoka 120a6e
  UCHAR m_hasColor, m_hasRegion;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void getBoundaries(TVectorImage &vi, std::vector<int> &strokes) {</int>
Shinya Kitaoka 120a6e
  enum { FORWARD = 0x1, BACKWARD = 0x2, INTERNAL = FORWARD | BACKWARD };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    static inline bool isBoundary(const std::vector<strokedata> &sData,</strokedata>
Shinya Kitaoka 120a6e
                                  UINT s) {
Shinya Kitaoka 120a6e
      return (sData[s].m_hasColor != INTERNAL);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static void markEdges(const TRegion ®ion, std::vector<strokedata> &sData,</strokedata>
Shinya Kitaoka 120a6e
                          bool parentRegionHasColor) {
Shinya Kitaoka 120a6e
      bool regionHasColor = (region.getStyle() != 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Traverse region edges, marking associated strokes accordingly
Shinya Kitaoka 120a6e
      UINT e, eCount = region.getEdgeCount();
Shinya Kitaoka 120a6e
      for (e = 0; e != eCount; ++e) {
Shinya Kitaoka 120a6e
        const TEdge &ed = *region.getEdge(e);
Shinya Kitaoka 120a6e
        assert(ed.m_s);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        int strokeIdx = ed.m_index;
Shinya Kitaoka 120a6e
        if (strokeIdx >= 0)  // Could be <0 in case the corresponding
Shinya Kitaoka 120a6e
        {                    // stroke is a region 'closure' (autoclose)
Shinya Kitaoka 120a6e
          assert(0 <= strokeIdx && strokeIdx < sData.size());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          StrokeData &sd = sData[strokeIdx];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          UCHAR side = (ed.m_w1 > ed.m_w0) ? FORWARD : BACKWARD;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          sd.m_hasRegion |= side;
Shinya Kitaoka 120a6e
          if (regionHasColor) sd.m_hasColor |= side;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (parentRegionHasColor) {
Shinya Kitaoka 120a6e
        // Mark non-region edge sides with color
Shinya Kitaoka 120a6e
        for (e = 0; e != eCount; ++e) {
Shinya Kitaoka 120a6e
          const TEdge &ed = *region.getEdge(e);
Shinya Kitaoka 120a6e
          assert(ed.m_s);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          int strokeIdx = ed.m_index;
Shinya Kitaoka 120a6e
          if (strokeIdx >= 0) {
Shinya Kitaoka 120a6e
            StrokeData &sd = sData[strokeIdx];
Shinya Kitaoka 120a6e
            sd.m_hasColor |= (INTERNAL & ~sd.m_hasRegion);
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Mark recursively on sub-regions
Shinya Kitaoka 120a6e
      UINT sr, srCount = region.getSubregionCount();
Shinya Kitaoka 120a6e
      for (sr = 0; sr != srCount; ++sr)
Shinya Kitaoka 120a6e
        markEdges(*region.getSubregion(sr), sData, regionHasColor);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };  // locals
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<strokedata> sData(vi.getStrokeCount());</strokedata>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Traverse regions, mark each stroke edge with the side a COLORED region is
Shinya Kitaoka 120a6e
  // on
Shinya Kitaoka 120a6e
  UINT r, rCount = vi.getRegionCount();
Shinya Kitaoka 120a6e
  for (r = 0; r != rCount; ++r)
Shinya Kitaoka 120a6e
    locals::markEdges(*vi.getRegion(r), sData, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Strokes not appearing as region edges must be checked for region inclusion
Shinya Kitaoka 120a6e
  // separately
Shinya Kitaoka 120a6e
  UINT s, sCount = vi.getStrokeCount();
Shinya Kitaoka 120a6e
  for (s = 0; s != sCount; ++s) {
Shinya Kitaoka 120a6e
    if (!sData[s].m_hasRegion) {
Shinya Kitaoka 120a6e
      TRegion *parentRegion = vi.getRegion(vi.getStroke(s)->getPoint(0.5));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (parentRegion && parentRegion->getStyle())
Shinya Kitaoka 120a6e
        sData[s].m_hasColor = INTERNAL;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Output all not internal regions
Shinya Kitaoka 120a6e
  boost_a::copy_if(boost::make_counting_iterator(0u),
Shinya Kitaoka 120a6e
                   boost::make_counting_iterator(vi.getStrokeCount()),
Shinya Kitaoka 120a6e
                   std::back_inserter(strokes),
Shinya Kitaoka 120a6e
                   boost::bind(locals::isBoundary, sData, _1));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*******************************************************************************
Toshihiro Shimizu 890ddd
//    VectorLevelSelection  implementation
Toshihiro Shimizu 890ddd
//*******************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
LevelSelection::LevelSelection() : m_framesMode(FRAMES_NONE), m_filter(EMPTY) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool LevelSelection::isEmpty() const {
Shinya Kitaoka 120a6e
  return (m_framesMode == FRAMES_NONE || m_filter == EMPTY);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void LevelSelection::selectNone() {
Shinya Kitaoka 120a6e
  m_framesMode = FRAMES_NONE;
Shinya Kitaoka 120a6e
  m_filter     = EMPTY;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_styles.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*******************************************************************************
Toshihiro Shimizu 890ddd
//    Related standalone functions
Toshihiro Shimizu 890ddd
//*******************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::vector<int> getBoundaryStrokes(TVectorImage &vi) {</int>
Shinya Kitaoka 120a6e
  std::vector<int> result;</int>
Shinya Kitaoka 120a6e
  getBoundaries(vi, result);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::vector<int> getSelectedStrokes(TVectorImage &vi,</int>
Shinya Kitaoka 120a6e
                                    const LevelSelection &levelSelection) {
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    static void selectStyles(const TVectorImage &vi,
Shinya Kitaoka 120a6e
                             const std::set<int> &styles,</int>
Shinya Kitaoka 120a6e
                             std::vector<int> &strokes) {</int>
Shinya Kitaoka 120a6e
      UINT s, sCount = vi.getStrokeCount();
Shinya Kitaoka 120a6e
      for (s = 0; s != sCount; ++s) {
Shinya Kitaoka 120a6e
        if (styles.count(vi.getStroke(s)->getStyle())) strokes.push_back(s);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };  // locals
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<int> strokes;</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  switch (levelSelection.filter()) {
Shinya Kitaoka 120a6e
  case LevelSelection::EMPTY:
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case LevelSelection::WHOLE:
Shinya Kitaoka 120a6e
    strokes.assign(boost::make_counting_iterator(0u),
Shinya Kitaoka 120a6e
                   boost::make_counting_iterator(vi.getStrokeCount()));
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case LevelSelection::SELECTED_STYLES:
Shinya Kitaoka 120a6e
    locals::selectStyles(vi, levelSelection.styles(), strokes);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case LevelSelection::BOUNDARY_STROKES:
Shinya Kitaoka 120a6e
    getBoundaries(vi, strokes);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return strokes;
Toshihiro Shimizu 890ddd
}