#pragma once #ifndef _TVECTORIMAGEP_H_ #define _TVECTORIMAGEP_H_ #include "tstroke.h" #include "tvectorimage.h" #include "tregion.h" #include "tcurves.h" //----------------------------------------------------------------------------- class IntersectedStroke; class VIStroke; //============================================================================= class VIStroke; class TGroupId { public: std::vector m_id; // m_id[i-1] e' parent di m_id[i] TGroupId() : m_id() {} // 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 TGroupId(TVectorImage *vi, bool isGhost); TGroupId(const TGroupId &strokeGroup) : m_id(strokeGroup.m_id){}; // costruisce un gruppo partendo da un parent e da un id esistente. TGroupId(const TGroupId &parent, const TGroupId &id); bool operator==(const TGroupId &id) const; bool operator!=(const TGroupId &id) const { return !(*this == id); } // TGroupId makeGroup(vector strokes, bool recomputeRegions=false); // void unmakeGroup(vector strokes); // ritrona la depth del gruppo. (0->not grouped) int isGrouped(bool implicit = false) const; // toglie il parent; se nera gruppo semplice, gli assegna il parametro id. void ungroup(const TGroupId &id); // bool sameParent(const TGroupId& id) const; bool operator!() const { return m_id.empty() || m_id[0] == 0; }; bool operator<(const TGroupId &id) const; int getDepth() const { return m_id.size(); } int getCommonParentDepth(const TGroupId &id) const; TGroupId getParent() const; int isParentOf(const TGroupId &id) const { return getCommonParentDepth(id) == getDepth(); } }; class VIStroke { public: TStroke *m_s; bool m_isPoint; bool m_isNewForFill; std::list 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::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::iterator it = m_edgeList.begin(); while (it != m_edgeList.end() && *it != e) it++; if (*it == e) { m_edgeList.erase(it); return true; } return false; } }; //----------------------------------------------------------------------------- class IntersectionData; class Intersection; // class IntersectStroke; #ifdef LEVO class TAutocloseEdge final : public TGeneralEdge { public: 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) {} }; #endif //--------------------------------------------------------------------------------------------------- class TRegionFinder; class TVectorImage::Imp { TVectorImage *m_vi; public: 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 m_strokes; double m_autocloseTolerance; IntersectionData *m_intersectionData; std::vector 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 &indexes, bool areAdded); void checkRegionDbConsistency(); void cloneRegions(TVectorImage::Imp &out, bool doComputeRegions = true); void eraseIntersection(int index); UINT getFillData(std::unique_ptr &v); void setFillData(std::unique_ptr const &v, UINT branchCount, bool doComputeRegions = true); void notifyChangedStrokes(const std::vector &strokeIndexArray, const std::vector &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 &toBeRemoved, bool deleteThem, bool recomputeRegions); TStroke *removeStroke(int index, bool doComputeRegions); void splitStroke(int strokeIndex, const std::vector &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 &changedStrokes); bool inCurrentGroup(int strokeIndex) const; bool canMoveStrokes(int strokeIndex, int count, int moveBefore) const; #ifdef _DEBUG void checkIntersections(); void checkRegions(const std::vector ®ions); void printStrokes(std::ofstream &os); void checkGroups(); #endif #ifdef NEW_REGION_FILL TRegionFinder *m_regionFinder; void resetRegionFinder(); #endif private: 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 *toBeDeleted = 0); void eraseEdgeFromStroke(IntersectedStroke *is); bool areWholeGroups(const std::vector &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 // REGIONI------------------------------------------------ public: #ifdef LEVO vector existingRegions; TRegion *findRegionFromStroke(const IntersectStroke &stroke, const TPointD &p); bool findNextStrokes(const TEdge &currEdge, std::multimap &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 &segments); void computeAutocloseSegmentsSameStroke( const TEdge &currEdge, std::multimap &segments); #endif //-------------------------------------------------------------------------------------- private: // not implemented Imp(const Imp &); Imp &operator=(const Imp &); }; void addRegion(std::vector ®ionArray, TRegion *region); //============================================================================= #endif