summaryrefslogtreecommitdiff
path: root/inc/Poly_MakeLoops.hxx
blob: fdbc57354ac939529cb9753403c274aa9191f193 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
// File:        Poly_MakeLoops.hxx
// Created:     22.10.2009
// Author:      Mikhail SAZONOV
// Copyright:   Open Cascade 2009

#ifndef Poly_MakeLoops_HeaderFile
#define Poly_MakeLoops_HeaderFile

#include <NCollection_Sequence.hxx>
#include <NCollection_IndexedMap.hxx>
#include <TColStd_PackedMapOfInteger.hxx>
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
#include <NCollection_BaseAllocator.hxx>
#include <NCollection_List.hxx>

class Handle_NCollection_IncAllocator;

/**
 * Make loops from a set of connected links. A link is represented by 
 * a pair of integer indices of nodes.
 */
class Poly_MakeLoops
{
public:
  //! Orientation flags that can be attached to a link
  enum LinkFlag {
    LF_None  = 0,
    LF_Fwd   = 1,    // forward orientation
    LF_Rev   = 2,    // reversed orientation
    LF_Both  = 3,    // both ways oriented
    LF_Reversed = 4  // means the link is reversed
  };

  //! The Link structure
  struct Link
  {
    Standard_Integer node1, node2;
    Standard_Integer flags;

    Link()
      : node1(0), node2(0), flags(0) {}

    Link(Standard_Integer theNode1, Standard_Integer theNode2)
      : node1(theNode1), node2(theNode2), flags(0) {}

    void Reverse()
    {
      flags ^= Poly_MakeLoops::LF_Reversed;
    }

    Standard_Boolean IsReversed() const
    {
      return flags & Poly_MakeLoops::LF_Reversed;
    }

    void Nullify()
    {
      node1 = node2 = 0;
    }

    Standard_Boolean IsNull() const
    {
      return node1 == 0 || node2 == 0;
    }
  };

  // Define the Loop as a list of links
  typedef NCollection_List<Link> ListOfLink;
  typedef ListOfLink Loop;

  //! The abstract helper class
  class Helper
  {
  public:
    //! returns the links adjacent to the given node
    virtual const ListOfLink& GetAdjacentLinks (Standard_Integer theNode) const = 0;
    //! hook function called from AddLink in _DEBUG mode
    virtual void OnAddLink (Standard_Integer /*theNum*/, const Link& /*theLink*/) const {}
  };

  //! This class implements a heap of integers. The most effective usage
  //! of it is first to add there all items, and then get top item and remove
  //! any items till it becomes empty.
  class HeapOfInteger
  {
  public:
    HeapOfInteger (const Standard_Integer theNbPreAllocated = 1)
      : myMap (theNbPreAllocated),
        myIterReady (Standard_False) {}

    void Clear()
    {
      myMap.Clear();
      myIterReady = Standard_False;
    }

    void Add (const Standard_Integer theValue)
    {
      myMap.Add (theValue);
      myIterReady = Standard_False;
    }

    Standard_Integer Top()
    {
      if (!myIterReady)
      {
        myIter.Initialize (myMap);
        myIterReady = Standard_True;
      }
      return myIter.Key();
    }

    Standard_Boolean Contains (const Standard_Integer theValue) const
    {
      return myMap.Contains (theValue);
    }

    void Remove (const Standard_Integer theValue)
    {
      if (myIterReady && myIter.More() && myIter.Key() == theValue)
        myIter.Next();
      myMap.Remove (theValue);
    }

    Standard_Boolean IsEmpty()
    {
      if (!myIterReady)
      {
        myIter.Initialize (myMap);
        myIterReady = Standard_True;
      }
      return !myIter.More();
    }

  private:
    TColStd_PackedMapOfInteger              myMap;
    TColStd_MapIteratorOfPackedMapOfInteger myIter;
    Standard_Boolean                        myIterReady;
  };

public:
  // PUBLIC METHODS

  //! Constructor. If helper is NULL then the algorithm will
  //! probably return a wrong result
  Standard_EXPORT Poly_MakeLoops(const Helper* theHelper,
                                 const Handle_NCollection_BaseAllocator& theAlloc = 0L);

  //! It is to reset the algorithm to the initial state.
  Standard_EXPORT void Reset
                   (const Helper* theHelper,
                    const Handle_NCollection_BaseAllocator& theAlloc = 0L);

  //! Adds a link to the set. theOrient defines which orientations of the link
  //! are allowed.
  Standard_EXPORT void AddLink(const Link& theLink);

  //! Replace one link with another (e.g. to change order of nodes)
  Standard_EXPORT void ReplaceLink(const Link& theLink, const Link& theNewLink);

  //! Set a new value of orientation of a link already added earlier.
  //! It can be used with LF_None to exclude the link from consideration.
  //! Returns the old value of orienation.
  Standard_EXPORT LinkFlag SetLinkOrientation
                   (const Link& theLink,
                    const LinkFlag theOrient);

  //! Find the link stored in algo by value
  Standard_EXPORT Link FindLink(const Link& theLink) const;

  enum ResultCode
  {
    RC_LoopsDone    = 1,
    RC_HangingLinks = 2,
    RC_Failure      = 4
  };

  //! Does the work. Returns the collection of result codes
  Standard_EXPORT Standard_Integer Perform();

  //! Returns the number of loops in the result
  Standard_Integer GetNbLoops() const
  {
    return myLoops.Length();
  }

  //! Returns the loop of the given index
  const Loop& GetLoop(Standard_Integer theIndex) const
  {
    return myLoops.Value(theIndex);
  }

  //! Returns the number of detected hanging chains
  Standard_Integer GetNbHanging() const
  {
    return myHangIndices.Extent();
  }

  //! Fills in the list of hanging links
  void GetHangingLinks(ListOfLink& theLinks) const;

protected:
  virtual Standard_Integer chooseLeftWay
                   (const Standard_Integer theNode,
                    const Standard_Integer theSegIndex,
                    const NCollection_List<Standard_Integer>& theLstIndS) const = 0;

  const Helper* getHelper () const
  {
    return myHelper;
  }

  Link getLink (const Standard_Integer theSegIndex) const
  {
    Link aLink = myMapLink(Abs(theSegIndex));
    if (theSegIndex < 0)
      aLink.Reverse();
    return aLink;
  }
#ifdef _DEBUG
  void showBoundaryBreaks() const;
#endif

private:
  int findContour(Standard_Integer theIndexS, NCollection_IndexedMap<Standard_Integer>& theContour,
                  const Handle_NCollection_BaseAllocator& theTempAlloc,
                  const Handle_NCollection_IncAllocator& theTempAlloc1) const;
  void acceptContour(const NCollection_IndexedMap<Standard_Integer>& theContour,
                     Standard_Integer theStartNumber);
  Standard_Integer getFirstNode(Standard_Integer theIndexS) const;
  Standard_Integer getLastNode(Standard_Integer theIndexS) const;
  void markHangChain(Standard_Integer theNode, Standard_Integer theIndexS);
  Standard_Boolean canLinkBeTaken(Standard_Integer theIndexS) const;

  // FIELDS
  const Helper*                           myHelper;
  Handle_NCollection_BaseAllocator        myAlloc;
  NCollection_IndexedMap<Link>            myMapLink;
  NCollection_Sequence<Loop>              myLoops;
  HeapOfInteger                           myStartIndices;
  TColStd_PackedMapOfInteger              myHangIndices;
};

/**
 * HashCode method is needed for maps
 */
inline Standard_Integer HashCode(const Poly_MakeLoops::Link& theKey,
                    int theLimit)
{
  return HashCode(theKey.node1 + theKey.node2, theLimit);
}

/**
 * IsEqual method is needed for maps
 */
inline Standard_Boolean IsEqual(const Poly_MakeLoops::Link& theKey1,
                                const Poly_MakeLoops::Link& theKey2)
{
  return ((theKey1.node1 == theKey2.node1 &&
           theKey1.node2 == theKey2.node2) ||
          (theKey1.node1 == theKey2.node2 &&
           theKey1.node2 == theKey2.node1));
}

/**
 * Implementation for 3D space
 */
class gp_Dir;
class Poly_MakeLoops3D: public Poly_MakeLoops
{
public:
  //! The abstract helper class
  class Helper: public Poly_MakeLoops::Helper
  {
  public:
    // all the following methods should return False if 
    // it is impossible to return a valid direction

    //! returns the tangent vector at the first node of a link
    virtual Standard_Boolean GetFirstTangent(const Link& theLink,
                                             gp_Dir& theDir) const = 0;

    //! returns the tangent vector at the last node of a link
    virtual Standard_Boolean GetLastTangent(const Link& theLink,
                                            gp_Dir& theDir) const = 0;

    //! returns the normal to the surface at a given node
    virtual Standard_Boolean GetNormal(Standard_Integer theNode,
                                       gp_Dir& theDir) const = 0;
  };

  //! Constructor. If helper is NULL then the algorithm will
  //! probably return a wrong result
  Standard_EXPORT Poly_MakeLoops3D(const Helper* theHelper,
                                      const Handle_NCollection_BaseAllocator& theAlloc);

protected:
  Standard_EXPORT virtual Standard_Integer chooseLeftWay
                   (const Standard_Integer theNode,
                    const Standard_Integer theSegIndex,
                    const NCollection_List<Standard_Integer>& theLstIndS) const;
  const Helper* getHelper () const
  {
    return static_cast<const Poly_MakeLoops3D::Helper*>
      (Poly_MakeLoops::getHelper());
  }
};

/**
 * Implementation for 2D space
 */
class gp_Dir2d;
class Poly_MakeLoops2D: public Poly_MakeLoops
{
public:
  //! The abstract helper class
  class Helper: public Poly_MakeLoops::Helper
  {
  public:
    // all the following methods should return False if 
    // it is impossible to return a valid direction

    //! returns the tangent vector at the first node of a link
    virtual Standard_Boolean GetFirstTangent(const Link& theLink,
                                             gp_Dir2d& theDir) const = 0;

    //! returns the tangent vector at the last node of a link
    virtual Standard_Boolean GetLastTangent(const Link& theLink,
                                            gp_Dir2d& theDir) const = 0;
  };

  //! Constructor. If helper is NULL then the algorithm will
  //! probably return a wrong result
  Standard_EXPORT Poly_MakeLoops2D(const Standard_Boolean theLeftWay,
                                      const Helper* theHelper,
                                      const Handle_NCollection_BaseAllocator& theAlloc);

protected:
  Standard_EXPORT virtual Standard_Integer chooseLeftWay
                   (const Standard_Integer theNode,
                    const Standard_Integer theSegIndex,
                    const NCollection_List<Standard_Integer>& theLstIndS) const;
  const Helper* getHelper () const
  {
    return static_cast<const Poly_MakeLoops2D::Helper*>
      (Poly_MakeLoops::getHelper());
  }

private:
  //! this flag says that chooseLeftWay must choose the right way instead
  Standard_Boolean myRightWay;
};

#endif