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