1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif // HAVE_CONFIG_H
36
37 #ifdef HAVE_NODEKITS
38
39 /*!
40 \class SoNodeKitPath SoNodeKitPath.h Inventor/SoNodeKitPath.h
41 \brief The SoNodeKitPath class is a path that contains only nodekit nodes.
42
43 \ingroup nodekits
44
45 All other nodes are hidden from the user.
46 */
47
48 // FIXME: We now need a "friend class SoNodeKitPath;" in the SoPath
49 // definition -- could we do without it? That would clean up the
50 // implementation a bit. 20020119 mortene.
51
52 #include <Inventor/SoNodeKitPath.h>
53
54 #include <cstdlib>
55
56 #include <Inventor/nodekits/SoBaseKit.h>
57 #include <Inventor/actions/SoSearchAction.h>
58
59 #include "tidbitsp.h"
60
61 #if COIN_DEBUG
62 #include <Inventor/errors/SoDebugError.h>
63 #endif // COIN_DEBUG
64
65 SoSearchAction * SoNodeKitPath::searchAction;
66
67 /*!
68 A constructor.
69 */
SoNodeKitPath(const int approxLength)70 SoNodeKitPath::SoNodeKitPath(const int approxLength)
71 : SoPath(approxLength)
72 {
73 #if COIN_DEBUG
74 int n = this->nodes.getLength();
75 for (int i = 0; i < n; i++) {
76 if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId()))
77 return;
78 }
79 SoDebugError::postInfo("SoNodeKitPath::SoNodeKitPath",
80 "no nodekits in path");
81 #endif // COIN_DEBUG
82 }
83
84 /*!
85 The destructor.
86 */
~SoNodeKitPath()87 SoNodeKitPath::~SoNodeKitPath()
88 {
89 }
90
91 /*!
92 Returns the length of the path (the number of nodekit nodes).
93 */
94 int
getLength(void) const95 SoNodeKitPath::getLength(void) const
96 {
97 int n = this->nodes.getLength();
98 int cnt = 0;
99 for (int i = 0; i < n; i++) {
100 if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId())) cnt++;
101 }
102 return cnt;
103 }
104
105 /*!
106 Returns the tail of the path (the last nodekit in the path).
107 */
108 SoNode *
getTail(void) const109 SoNodeKitPath::getTail(void) const
110 {
111 for (int i = this->nodes.getLength()-1; i >= 0; i--) {
112 if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId()))
113 return this->nodes[i];
114 }
115 #if COIN_DEBUG && 1 // debug
116 SoDebugError::postInfo("SoNodeKitPath::getTail",
117 "no nodekit in path");
118 #endif // debug
119 return NULL;
120 }
121
122 /*!
123 Returns nodekit number \a idx in path.
124 */
125 SoNode *
getNode(const int idx) const126 SoNodeKitPath::getNode(const int idx) const
127 {
128 int n = this->nodes.getLength();
129 int cnt = 0;
130 for (int i = 0; i < n; i++) {
131 if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId())) {
132 if (cnt++ == idx) return this->nodes[i];
133 }
134 }
135 #if COIN_DEBUG
136 SoDebugError::postInfo("SoNodeKitPath::getNode",
137 "index %d out of bounds", idx);
138 #endif // COIN_DEBUG
139
140 return NULL;
141 }
142
143 /*!
144 Returns nodekit number \a idx in the path, from the tail.
145 */
146 SoNode *
getNodeFromTail(const int idx) const147 SoNodeKitPath::getNodeFromTail(const int idx) const
148 {
149 int cnt = 0;
150 for (int i = this->nodes.getLength()-1; i >=0; i--) {
151 if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId())) {
152 if (cnt++ == idx) return this->nodes[i];
153 }
154 }
155 #if COIN_DEBUG
156 SoDebugError::postInfo("SoNodeKitPath::getNodeFromTail",
157 "index %d out of bounds", idx);
158 #endif // COIN_DEBUG
159 return NULL;
160 }
161
162 /*!
163 Truncates the path at nodekit number \a length.
164 */
165 void
truncate(const int length)166 SoNodeKitPath::truncate(const int length)
167 {
168 int i, n = this->nodes.getLength();
169 int cnt = 0;
170 for (i = 0; i < n; i++) {
171 if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId())) {
172 if (cnt++ == length) break;
173 }
174 }
175 if (i < n) SoPath::truncate(i);
176 #if COIN_DEBUG
177 else {
178 SoDebugError::postInfo("SoNodeKitPath::truncate",
179 "illegal length: %d", length);
180 }
181 #endif // COIN_DEBUG
182 }
183
184 /*!
185 Pops off the last nodekit (truncates at last tail).
186 */
187 void
pop(void)188 SoNodeKitPath::pop(void)
189 {
190 int i = this->nodes.getLength() - 1;
191 for (; i >= 0; i--) {
192 if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId())) break;
193 }
194 if (i < 0) {
195 #if COIN_DEBUG
196 SoDebugError::postInfo("SoNodeKitPath::pop",
197 "no nodekits in path");
198 #endif // COIN_DEBUG
199 return;
200 }
201 SoPath::truncate(i);
202 }
203
204 /*!
205 Appends \a childKit to the path. childKit should be a part in the
206 tail nodekit of this path. In effect, the path from the tail to first
207 occurrance of \a childKit will be appended to the path.
208 */
209 void
append(SoBaseKit * childKit)210 SoNodeKitPath::append(SoBaseKit * childKit)
211 {
212 if (this->getLength() == 0) this->setHead(childKit);
213 else {
214 SoBaseKit * tail = (SoBaseKit *) this->getTail();
215 assert(tail != NULL);
216 SoSearchAction * sa = this->getSearchAction();
217 sa->setNode(childKit);
218 SbBool oldSearch = tail->isSearchingChildren();
219 tail->setSearchingChildren(TRUE);
220 sa->apply(tail);
221 tail->setSearchingChildren(oldSearch);
222 SoPath * path = sa->getPath();
223 if (path) SoPath::append(path);
224 else {
225 #if COIN_DEBUG
226 SoDebugError::postInfo("SoNodeKitPath::append",
227 "childKit not found as part of tail");
228 #endif // COIN_DEBUG
229 }
230 }
231 }
232
233 /*!
234 Appends the nodekit path to this path. Head of \a fromPath must
235 be a part in the current tail.
236 */
237 void
append(const SoNodeKitPath * fromPath)238 SoNodeKitPath::append(const SoNodeKitPath * fromPath)
239 {
240 int n = fromPath->getLength();
241 for (int i = 0; i < n; i++) {
242 this->append((SoBaseKit *)fromPath->getNode(i));
243 }
244 }
245
246 /*!
247 Returns \c TRUE if \a node is in this path.
248 */
249 SbBool
containsNode(SoBaseKit * node) const250 SoNodeKitPath::containsNode(SoBaseKit * node) const
251 {
252 return SoPath::containsNode((SoNode *)node);
253 }
254
255 /*!
256 Returns the index of last common nodekit, or -1 if head
257 node differs.
258 */
259 int
findFork(const SoNodeKitPath * path) const260 SoNodeKitPath::findFork(const SoNodeKitPath * path) const
261 {
262 int i, n = SbMin(this->getLength(), path->getLength());
263 for (i = 0; i < n; i++) {
264 if (this->getNode(i) != path->getNode(i)) break;
265 }
266 return i-1;
267 }
268
269 /*!
270 Returns \c TRUE if paths are equal, \c FALSE otherwise.
271 */
272 int
operator ==(const SoNodeKitPath & p1,const SoNodeKitPath & p2)273 operator==(const SoNodeKitPath & p1, const SoNodeKitPath & p2)
274 {
275 if (&p1 == &p2) return TRUE;
276 int n = p1.getLength();
277 if (n != p2.getLength()) return FALSE;
278
279 for (int i = 0; i < n; i++) {
280 if (p1.getNode(i) != p2.getNode(i)) return FALSE;
281 }
282 return TRUE;
283 }
284
285
286 //
287 // atexit() method
288 //
289 void
clean(void)290 SoNodeKitPath::clean(void)
291 {
292 delete SoNodeKitPath::searchAction;
293 SoNodeKitPath::searchAction = NULL;
294 }
295
296 //
297 // returns a search action to be used while serching for nodes
298 //
299 SoSearchAction *
getSearchAction(void)300 SoNodeKitPath::getSearchAction(void)
301 {
302 if (SoNodeKitPath::searchAction == NULL) {
303 SoNodeKitPath::searchAction = new SoSearchAction();
304 searchAction->setInterest(SoSearchAction::FIRST);
305 searchAction->setSearchingAll(FALSE);
306 coin_atexit((coin_atexit_f *)SoNodeKitPath::clean, CC_ATEXIT_NORMAL);
307 }
308 return SoNodeKitPath::searchAction;
309 }
310
311 //
312 // private methods, just to keep the user from making mistakes
313 //
314
315 void
append(const int)316 SoNodeKitPath::append(const int)
317 {
318
319 }
320
321 void
append(SoNode *)322 SoNodeKitPath::append(SoNode *)
323 {
324 }
325
326 void
append(const SoPath *)327 SoNodeKitPath::append(const SoPath *)
328 {
329 }
330
331 void
push(const int)332 SoNodeKitPath::push(const int)
333 {
334 }
335
336 int
getIndex(const int) const337 SoNodeKitPath::getIndex(const int) const
338 {
339 return 0;
340 }
341
342 int
getIndexFromTail(const int) const343 SoNodeKitPath::getIndexFromTail(const int) const
344 {
345 return 0;
346 }
347
348 void
insertIndex(SoNode *,const int)349 SoNodeKitPath::insertIndex(SoNode *, const int)
350 {
351 }
352
353 void
removeIndex(SoNode *,const int)354 SoNodeKitPath::removeIndex(SoNode *,const int)
355 {
356 }
357
358 void
replaceIndex(SoNode *,const int,SoNode *)359 SoNodeKitPath::replaceIndex(SoNode *, const int, SoNode *)
360 {
361 }
362
363 #endif // HAVE_NODEKITS
364