2016-05-17 03:04:11 +12:00
|
|
|
#pragma once
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#ifndef _TVECTORIMAGEP_H_
|
|
|
|
#define _TVECTORIMAGEP_H_
|
|
|
|
|
|
|
|
#include "tstroke.h"
|
|
|
|
#include "tvectorimage.h"
|
|
|
|
#include "tregion.h"
|
|
|
|
#include "tcurves.h"
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
class IntersectedStroke;
|
|
|
|
class VIStroke;
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
class VIStroke;
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
class TGroupId {
|
2016-03-19 06:57:51 +13:00
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
std::vector<int> m_id; // m_id[i-1] e' parent di m_id[i]
|
|
|
|
TGroupId() : m_id() {}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// ghost group sono i gruppi impliciti: tutti gli stroke che non fanno parte
|
|
|
|
// di nessun gruppo ma
|
|
|
|
// che stanno tra due gruppi fanno parte di un gruppo implicito. per
|
|
|
|
// convenzione un ghostGroup ha id<0
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TGroupId(TVectorImage *vi, bool isGhost);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TGroupId(const TGroupId &strokeGroup) : m_id(strokeGroup.m_id){};
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// costruisce un gruppo partendo da un parent e da un id esistente.
|
|
|
|
TGroupId(const TGroupId &parent, const TGroupId &id);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool operator==(const TGroupId &id) const;
|
|
|
|
bool operator!=(const TGroupId &id) const { return !(*this == id); }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// TGroupId makeGroup(vector<VIStroke*> strokes, bool recomputeRegions=false);
|
|
|
|
// void unmakeGroup(vector<VIStroke*> strokes);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// ritrona la depth del gruppo. (0->not grouped)
|
|
|
|
int isGrouped(bool implicit = false) const;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// toglie il parent; se nera gruppo semplice, gli assegna il parametro id.
|
|
|
|
void ungroup(const TGroupId &id);
|
|
|
|
// bool sameParent(const TGroupId& id) const;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool operator!() const { return m_id.empty() || m_id[0] == 0; };
|
|
|
|
bool operator<(const TGroupId &id) const;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
int getDepth() const { return m_id.size(); }
|
|
|
|
int getCommonParentDepth(const TGroupId &id) const;
|
|
|
|
TGroupId getParent() const;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
int isParentOf(const TGroupId &id) const {
|
|
|
|
return getCommonParentDepth(id) == getDepth();
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
class VIStroke {
|
2016-03-19 06:57:51 +13:00
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
TStroke *m_s;
|
|
|
|
bool m_isPoint;
|
|
|
|
bool m_isNewForFill;
|
|
|
|
std::list<TEdge *> m_edgeList;
|
|
|
|
TGroupId m_groupId;
|
|
|
|
|
|
|
|
VIStroke(TStroke *s, const TGroupId &StrokeId)
|
|
|
|
: m_s(s), m_isPoint(false), m_isNewForFill(true), m_groupId(StrokeId){};
|
|
|
|
|
|
|
|
VIStroke(const VIStroke &s, bool sameId = true);
|
|
|
|
|
|
|
|
~VIStroke() {
|
|
|
|
delete m_s;
|
|
|
|
|
|
|
|
std::list<TEdge *>::iterator it, it_b = m_edgeList.begin(),
|
|
|
|
it_e = m_edgeList.end();
|
|
|
|
for (it = it_b; it != it_e; ++it)
|
|
|
|
if ((*it)->m_toBeDeleted) delete *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
void inline addEdge(TEdge *e) { m_edgeList.push_back(e); }
|
|
|
|
|
|
|
|
bool inline removeEdge(TEdge *e) {
|
|
|
|
std::list<TEdge *>::iterator it = m_edgeList.begin();
|
|
|
|
while (it != m_edgeList.end() && *it != e) it++;
|
|
|
|
if (*it == e) {
|
|
|
|
m_edgeList.erase(it);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class IntersectionData;
|
|
|
|
class Intersection;
|
2016-06-15 18:43:10 +12:00
|
|
|
// class IntersectStroke;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#ifdef LEVO
|
|
|
|
|
2016-06-29 18:17:12 +12:00
|
|
|
class TAutocloseEdge final : public TGeneralEdge {
|
2016-03-19 06:57:51 +13:00
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
TSegment m_segment;
|
|
|
|
int m_nextStrokeIndex;
|
|
|
|
double m_nextStrokeW;
|
|
|
|
|
|
|
|
TAutocloseEdge(const TSegment &segment, int nextStrokeIndex,
|
|
|
|
double nextStrokeW)
|
|
|
|
: TGeneralEdge(eAutoclose)
|
|
|
|
, m_segment(segment)
|
|
|
|
, m_nextStrokeIndex(nextStrokeIndex)
|
|
|
|
, m_nextStrokeW(nextStrokeW) {}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------
|
|
|
|
class TRegionFinder;
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
class TVectorImage::Imp {
|
|
|
|
TVectorImage *m_vi;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
int m_maxGroupId;
|
|
|
|
int m_maxGhostGroupId;
|
|
|
|
|
|
|
|
bool m_areValidRegions;
|
|
|
|
bool m_computedAlmostOnce;
|
|
|
|
bool m_justLoaded;
|
|
|
|
bool m_minimizeEdges;
|
|
|
|
bool m_notIntersectingStrokes, m_computeRegions;
|
|
|
|
TGroupId m_insideGroup;
|
|
|
|
|
|
|
|
std::vector<VIStroke *> m_strokes;
|
|
|
|
double m_autocloseTolerance;
|
|
|
|
IntersectionData *m_intersectionData;
|
|
|
|
std::vector<TRegion *> m_regions;
|
|
|
|
TThread::Mutex *m_mutex;
|
|
|
|
Imp(TVectorImage *vi);
|
|
|
|
~Imp();
|
|
|
|
|
|
|
|
void initRegionsData();
|
|
|
|
void deleteRegionsData();
|
|
|
|
|
|
|
|
TRegion *getRegion(const TPointD &p);
|
|
|
|
|
|
|
|
int fill(const TPointD &p, int styleId);
|
|
|
|
bool selectFill(const TRectD &selectArea, TStroke *s, int styleId,
|
|
|
|
bool onlyUnfilled, bool fillAreas, bool fillLines);
|
|
|
|
|
|
|
|
void addStrokeRegionRef(UINT strokeIndex, TRegion *region);
|
|
|
|
|
|
|
|
int computeRegions();
|
|
|
|
void reindexEdges(UINT strokeIndex);
|
|
|
|
void reindexEdges(const std::vector<int> &indexes, bool areAdded);
|
|
|
|
|
|
|
|
void checkRegionDbConsistency();
|
|
|
|
void cloneRegions(TVectorImage::Imp &out, bool doComputeRegions = true);
|
|
|
|
|
|
|
|
void eraseIntersection(int index);
|
|
|
|
UINT getFillData(std::unique_ptr<TVectorImage::IntersectionBranch[]> &v);
|
|
|
|
void setFillData(std::unique_ptr<TVectorImage::IntersectionBranch[]> const &v,
|
|
|
|
UINT branchCount, bool doComputeRegions = true);
|
|
|
|
void notifyChangedStrokes(const std::vector<int> &strokeIndexArray,
|
|
|
|
const std::vector<TStroke *> &oldVectorStrokeArray,
|
|
|
|
bool areFlipped);
|
|
|
|
void insertStrokeAt(VIStroke *stroke, int strokeIndex,
|
|
|
|
bool recomputeRegions = true);
|
|
|
|
void moveStroke(int fromIndex, int toIndex);
|
|
|
|
void autoFill(int styleId, bool oddLevel);
|
|
|
|
|
|
|
|
TRegion *getRegion(TRegionId regId, int index) const;
|
|
|
|
TRegion *getRegionFromLoopStroke(int strokeIndex) const;
|
|
|
|
VIStroke *joinStroke(int index1, int index2, int cpIndex1, int cpIndex2);
|
|
|
|
VIStroke *joinStrokeSmoothly(int index1, int index2, int cpIndex1,
|
|
|
|
int cpIndex2);
|
|
|
|
VIStroke *extendStroke(int index, const TThickPoint &p, int cpIndex);
|
|
|
|
VIStroke *extendStrokeSmoothly(int index, const TThickPoint &p, int cpIndex);
|
|
|
|
void removeStrokes(const std::vector<int> &toBeRemoved, bool deleteThem,
|
|
|
|
bool recomputeRegions);
|
|
|
|
TStroke *removeStroke(int index, bool doComputeRegions);
|
|
|
|
void splitStroke(int strokeIndex,
|
|
|
|
const std::vector<DoublePair> &sortedWRanges);
|
|
|
|
void moveStrokes(int fromIndex, int count, int moveBefore, bool regroup);
|
|
|
|
|
|
|
|
TStroke *removeEndpoints(int strokeIndex);
|
|
|
|
void restoreEndpoints(int index, TStroke *oldStroke);
|
|
|
|
|
|
|
|
int areDifferentGroup(UINT index1, bool isRegion1, UINT index2,
|
|
|
|
bool isRegion2) const;
|
|
|
|
void rearrangeMultiGroup();
|
|
|
|
void reindexGroups(Imp &img);
|
|
|
|
void addRegion(TRegion *region);
|
|
|
|
void regroupGhosts(std::vector<int> &changedStrokes);
|
|
|
|
bool inCurrentGroup(int strokeIndex) const;
|
|
|
|
bool canMoveStrokes(int strokeIndex, int count, int moveBefore) const;
|
2016-03-19 06:57:51 +13:00
|
|
|
#ifdef _DEBUG
|
2016-06-15 18:43:10 +12:00
|
|
|
void checkIntersections();
|
|
|
|
void checkRegions(const std::vector<TRegion *> ®ions);
|
|
|
|
void printStrokes(std::ofstream &os);
|
|
|
|
void checkGroups();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2016-04-27 03:11:57 +12:00
|
|
|
#ifdef NEW_REGION_FILL
|
2016-06-15 18:43:10 +12:00
|
|
|
TRegionFinder *m_regionFinder;
|
|
|
|
void resetRegionFinder();
|
2016-04-27 03:11:57 +12:00
|
|
|
#endif
|
|
|
|
|
2016-03-19 06:57:51 +13:00
|
|
|
private:
|
2016-06-15 18:43:10 +12:00
|
|
|
void findRegions(const TRectD &rect);
|
|
|
|
int computeIntersections();
|
|
|
|
void findIntersections();
|
|
|
|
|
|
|
|
int computeEndpointsIntersections();
|
|
|
|
// Imp(const TVectorImage::Imp &);
|
|
|
|
// Imp & operator=(const TVectorImage::Imp &);
|
|
|
|
void eraseDeadIntersections();
|
|
|
|
IntersectedStroke *eraseBranch(Intersection *in, IntersectedStroke *is);
|
|
|
|
void doEraseIntersection(int index, std::vector<int> *toBeDeleted = 0);
|
|
|
|
void eraseEdgeFromStroke(IntersectedStroke *is);
|
|
|
|
bool areWholeGroups(const std::vector<int> &indexes) const;
|
|
|
|
// accorpa tutti i gruppi ghost adiacenti in uno solo, e rinomina gruppi ghost
|
|
|
|
// separati con lo stesso id; si usa questa funzione dopo ula creazione di un
|
|
|
|
// gruppo o il move di strokes
|
|
|
|
|
|
|
|
//--------------------NUOVO CALCOLO
|
2016-06-20 14:23:05 +12:00
|
|
|
// REGIONI------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
|
|
|
#ifdef LEVO
|
2016-06-15 18:43:10 +12:00
|
|
|
vector<TRegion *> existingRegions;
|
|
|
|
TRegion *findRegionFromStroke(const IntersectStroke &stroke,
|
|
|
|
const TPointD &p);
|
|
|
|
bool findNextStrokes(const TEdge &currEdge,
|
|
|
|
std::multimap<double, TGeneralEdge *> &nextEdges);
|
|
|
|
bool addNextEdge(TEdge &edge, TRegion ®ion, TRegion *&existingRegion,
|
|
|
|
bool isStartingEdge = false);
|
|
|
|
bool addNextEdge(TAutocloseEdge &edge, TRegion ®ion,
|
|
|
|
TRegion *&existingRegion);
|
|
|
|
bool storeRegion(TRegion *region, const TPointD &p);
|
|
|
|
|
|
|
|
bool exploreAndAddNextEdge(TEdge &edge, TEdge &nextEdge, TRegion ®ion,
|
|
|
|
TRegion *&existingRegion);
|
|
|
|
bool addNextAutocloseEdge(TEdge &edge, TAutocloseEdge &nextEdge,
|
|
|
|
TRegion ®ion, TRegion *&existingRegion);
|
|
|
|
bool addNextAutocloseEdge(TAutocloseEdge &edge, TEdge &nextEdge,
|
|
|
|
TRegion ®ion, TRegion *&existingRegion);
|
|
|
|
void computeAutocloseSegments(
|
|
|
|
const TEdge &currEdge, int strokeIndex,
|
|
|
|
std::multimap<double, TAutocloseEdge> &segments);
|
|
|
|
void computeAutocloseSegmentsSameStroke(
|
|
|
|
const TEdge &currEdge, std::multimap<double, TAutocloseEdge> &segments);
|
2016-03-19 06:57:51 +13:00
|
|
|
#endif
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//--------------------------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
private:
|
2016-06-15 18:43:10 +12:00
|
|
|
// not implemented
|
|
|
|
Imp(const Imp &);
|
|
|
|
Imp &operator=(const Imp &);
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
2016-07-22 16:38:33 +12:00
|
|
|
// Functions
|
|
|
|
|
2016-04-19 19:32:17 +12:00
|
|
|
void addRegion(std::vector<TRegion *> ®ionArray, TRegion *region);
|
2016-07-22 16:38:33 +12:00
|
|
|
|
|
|
|
void transferColors(const std::list<TEdge *> &oldList,
|
|
|
|
const std::list<TEdge *> &newList, bool isStrokeChanged,
|
|
|
|
bool isFlipped, bool overwriteColor);
|
|
|
|
|
2016-03-19 06:57:51 +13:00
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
#endif
|