1: <?php
2:
3: namespace Alpha\Util\Graph;
4:
5: use Alpha\Exception\IllegalArguementException;
6:
7: /**
8: * Maintains the geometry for a tree node.
9: *
10: * @since 1.0
11: *
12: * @author John Collins <dev@alphaframework.org>
13: * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
14: * @copyright Copyright (c) 2015, John Collins (founder of Alpha Framework).
15: * All rights reserved.
16: *
17: * <pre>
18: * Redistribution and use in source and binary forms, with or
19: * without modification, are permitted provided that the
20: * following conditions are met:
21: *
22: * * Redistributions of source code must retain the above
23: * copyright notice, this list of conditions and the
24: * following disclaimer.
25: * * Redistributions in binary form must reproduce the above
26: * copyright notice, this list of conditions and the
27: * following disclaimer in the documentation and/or other
28: * materials provided with the distribution.
29: * * Neither the name of the Alpha Framework nor the names
30: * of its contributors may be used to endorse or promote
31: * products derived from this software without specific
32: * prior written permission.
33: *
34: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
35: * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
36: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
37: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
39: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
44: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47: * </pre>
48: */
49: class GraphNode
50: {
51: /**
52: * The id of the node.
53: *
54: * @var int
55: *
56: * @since 1.0
57: */
58: private $id = 0;
59:
60: /**
61: * The height of the node.
62: *
63: * @var int
64: *
65: * @since 1.0
66: */
67: private $height = 0;
68:
69: /**
70: * The width of the node.
71: *
72: * @var int
73: *
74: * @since 1.0
75: */
76: private $width = 0;
77:
78: /**
79: * The x position of the node.
80: *
81: * @var int
82: *
83: * @since 1.0
84: */
85: private $x = 0;
86:
87: /**
88: * The y position of the node.
89: *
90: * @var int
91: *
92: * @since 1.0
93: */
94: private $y = 0;
95:
96: /**
97: * The node to the left of this one.
98: *
99: * @var Alpha\Util\Graph\GraphNode
100: *
101: * @since 1.0
102: */
103: private $leftNode;
104:
105: /**
106: * The node to the right of this one.
107: *
108: * @var Alpha\Util\Graph\GraphNode
109: *
110: * @since 1.0
111: */
112: private $rightNode;
113:
114: /**
115: * An array of child nodes of this node.
116: *
117: * @var array
118: *
119: * @since 1.0
120: */
121: private $children = array();
122:
123: /**
124: * The margin offset of the current node.
125: *
126: * @var int
127: *
128: * @since 1.0
129: */
130: private $offset = 0;
131:
132: /**
133: * Optional positional modifier.
134: *
135: * @var int
136: *
137: * @since 1.0
138: */
139: private $modifier = 0;
140:
141: /**
142: * Parent node of this node (if any).
143: *
144: * @var Alpha\Util\Graph\GraphNode
145: *
146: * @since 1.0
147: */
148: private $parentNode;
149:
150: /**
151: * The text message to display on the node.
152: *
153: * @var string
154: *
155: * @since 1.0
156: */
157: private $message;
158:
159: /**
160: * A 2D array of the coordinates of the endpoints for connectots on this node.
161: *
162: * @var array
163: *
164: * @since 1.0
165: */
166: private $links = array();
167:
168: /**
169: * An array containing the R,G,B values for the colour of this node.
170: *
171: * @var array
172: *
173: * @since 1.0
174: */
175: private $nodeColour;
176:
177: /**
178: * If the node is clickable in an image map, use this property to hold the target URL.
179: *
180: * @var string
181: *
182: * @since 1.0
183: */
184: private $URL;
185:
186: /**
187: * Constructor.
188: *
189: * @param int $id
190: * @param int $width
191: * @param int $height
192: * @param string $message
193: * @param array $nodeColour
194: * @param string $URL
195: */
196: public function __construct($id, $width, $height, $message = '', $nodeColour = null, $URL = null)
197: {
198: $this->id = $id;
199: $this->width = $width;
200: $this->height = $height;
201: $this->message = $message;
202: $this->nodeColour = $nodeColour;
203: $this->URL = $URL;
204: }
205:
206: /**
207: * Get the node colour array.
208: *
209: * @return array
210: *
211: * @since 1.0
212: */
213: public function getNodeColour()
214: {
215: return $this->nodeColour;
216: }
217:
218: /**
219: * Set the node colour array.
220: *
221: * @param array $nodeColour
222: *
223: * @throws Alpha\Exception\IllegalArguementException
224: *
225: * @since 1.0
226: */
227: public function setNodeColour($nodeColour)
228: {
229: if (is_array($nodeColour) && count($nodeColour) == 3) {
230: $this->nodeColour = $nodeColour;
231: } else {
232: throw new IllegalArguementException('The nodeColour value passed ['.$nodeColour.'] is not a valid array!');
233: }
234: }
235:
236: /**
237: * Get the node URL.
238: *
239: * @return string
240: *
241: * @since 1.0
242: */
243: public function getURL()
244: {
245: return $this->URL;
246: }
247:
248: /**
249: * Set the node URL.
250: *
251: * @param string $URL
252: *
253: * @since 1.0
254: */
255: public function setURL($URL)
256: {
257: $this->URL = $URL;
258: }
259:
260: /**
261: * Get the node text message.
262: *
263: * @return string
264: *
265: * @since 1.0
266: */
267: public function getMessage()
268: {
269: return $this->message;
270: }
271:
272: /**
273: * Set the node text message.
274: *
275: * @param string $message
276: *
277: * @since 1.0
278: */
279: public function setMessage($message)
280: {
281: $this->message = $message;
282: }
283:
284: /**
285: * Get the node offset.
286: *
287: * @return string
288: *
289: * @since 1.0
290: */
291: public function getOffset()
292: {
293: return $this->offset;
294: }
295:
296: /**
297: * Set the node offset.
298: *
299: * @param int $offset
300: *
301: * @since 1.0
302: */
303: public function setOffset($offset)
304: {
305: $this->offset = $offset;
306: }
307:
308: /**
309: * Get the node modifier.
310: *
311: * @return int
312: *
313: * @since 1.0
314: */
315: public function getModifier()
316: {
317: return $this->modifier;
318: }
319:
320: /**
321: * Set the node modifier.
322: *
323: * @param int $modifier
324: *
325: * @since 1.0
326: */
327: public function setModifier($modifier)
328: {
329: $this->modifier = $modifier;
330: }
331:
332: /**
333: * Get the number of child nodes attached to this node.
334: *
335: * @return int
336: *
337: * @since 1.0
338: */
339: public function childCount()
340: {
341: return count($this->children);
342: }
343:
344: /**
345: * Get the parent node of this node (if any).
346: *
347: * @return Alpha\Util\Graph\GraphNode
348: *
349: * @since 1.0
350: */
351: public function getParentNode()
352: {
353: return $this->parentNode;
354: }
355:
356: /**
357: * Set the parent node.
358: *
359: * @param Alpha\Util\Graph\GraphNode $node
360: *
361: * @throws Alpha\Exception\IllegalArguementException
362: *
363: * @since 1.0
364: */
365: public function setParentNode($node)
366: {
367: if ($node instanceof self) {
368: $this->parentNode = $node;
369: } else {
370: throw new IllegalArguementException('The node object passed to setParentNode is not a valid GraphNode instance!');
371: }
372: }
373:
374: /**
375: * Get the node to the left of this one (if any).
376: *
377: * @return Alpha\Util\Graph\GraphNode
378: *
379: * @since 1.0
380: */
381: public function getLeftSibling()
382: {
383: if ($this->leftNode) {
384: return $this->leftNode;
385: } else {
386: return;
387: }
388: }
389:
390: /**
391: * Sets the node to the left of this node.
392: *
393: * @param Alpha\Util\Graph\GraphNode $node
394: *
395: * @throws Alpha\Exception\IllegalArguementException
396: *
397: * @since 1.0
398: */
399: public function setLeftSibling($node)
400: {
401: if ($node instanceof self) {
402: $this->leftNode = $node;
403: } else {
404: throw new IllegalArguementException('The node object passed to setLeftSibling is not a valid GraphNode instance!');
405: }
406: }
407:
408: /**
409: * Get the node to the right of this one (if any).
410: *
411: * @return Alpha\Util\Graph\GraphNode
412: *
413: * @since 1.0
414: */
415: public function getRightSibling()
416: {
417: if ($this->rightNode) {
418: return $this->rightNode;
419: } else {
420: return;
421: }
422: }
423:
424: /**
425: * Sets the node to the right of this node.
426: *
427: * @param Alpha\Util\Graph\GraphNode $node
428: *
429: * @throws Alpha\Exception\IllegalArguementException
430: *
431: * @since 1.0
432: */
433: public function setRightSibling($node)
434: {
435: if ($node instanceof self) {
436: $this->rightNode = $node;
437: } else {
438: throw new IllegalArguementException('The node object passed to setRightSibling is not a valid GraphNode instance!');
439: }
440: }
441:
442: /**
443: * Gets the child node at the index provided, or returns false if none is found.
444: *
445: * @param int $i
446: *
447: * @return mixed
448: *
449: * @since 1.0
450: */
451: public function getChildAt($i)
452: {
453: if (isset($this->children[$i])) {
454: return $this->children[$i];
455: } else {
456: return false;
457: }
458: }
459:
460: /**
461: * Calculates and returns the midpoint X coordinate of the children of this node.
462: *
463: * @return int
464: *
465: * @since 1.0
466: */
467: public function getChildrenCenter()
468: {
469: $node = $this->getChildAt(0);
470: $node1 = $this->getChildAt(count($this->children) - 1);
471:
472: return $node->getOffset() + (($node1->getOffset() - $node->getOffset()) + $node1->getWidth()) / 2;
473: }
474:
475: /**
476: * Returns the array of child GraphNode objects.
477: *
478: * @return array
479: *
480: * @since 1.0
481: */
482: public function getChildren()
483: {
484: return $this->children;
485: }
486:
487: /**
488: * Add a new node to the children array of this node.
489: *
490: * @param Alpha\Util\Graph\GraphNode $node
491: *
492: * @throws ALpha\Exception\IllegalArguementException
493: *
494: * @since 1.0
495: */
496: public function addChild($node)
497: {
498: if ($node instanceof self) {
499: array_push($this->children, $node);
500: } else {
501: throw new IllegalArguementException('The node object passed to addChild is not a valid GraphNode instance!');
502: }
503: }
504:
505: /**
506: * Returns the links array.
507: *
508: * @return array
509: *
510: * @since 1.0
511: */
512: public function getLinks()
513: {
514: return $this->links;
515: }
516:
517: /**
518: * Sets up the array of connector endpoints.
519: *
520: * @since 1.0
521: */
522: public function setUpLinks()
523: {
524: $xa = 0;
525: $ya = 0;
526: $xb = 0;
527: $yb = 0;
528: $xc = 0;
529: $yc = 0;
530: $xd = 0;
531: $yd = 0;
532: $xa = $this->x + ($this->width / 2);
533: $ya = $this->y + $this->height;
534:
535: foreach ($this->children as $child) {
536: $xd = $xc = $child->getX() + ($child->getWidth() / 2);
537: $yd = $child->getY();
538: $xb = $xa;
539: $yb = $yc = $ya + ($yd - $ya) / 2;
540: $this->links[$child->id]['xa'] = $xa;
541: $this->links[$child->id]['ya'] = $ya;
542: $this->links[$child->id]['xb'] = $xb;
543: $this->links[$child->id]['yb'] = $yb;
544: $this->links[$child->id]['xc'] = $xc;
545: $this->links[$child->id]['yc'] = $yc;
546: $this->links[$child->id]['xd'] = $xd;
547: $this->links[$child->id]['yd'] = $yd;
548: }
549: }
550:
551: /**
552: * Returns the node height.
553: *
554: * @return int
555: *
556: * @since 1.0
557: */
558: public function getHeight()
559: {
560: return $this->height;
561: }
562:
563: /**
564: * Returns the node width.
565: *
566: * @return int
567: *
568: * @since 1.0
569: */
570: public function getWidth()
571: {
572: return $this->width;
573: }
574:
575: /**
576: * Returns the node X-coordinate.
577: *
578: * @return int
579: *
580: * @since 1.0
581: */
582: public function getX()
583: {
584: return $this->x;
585: }
586:
587: /**
588: * Returns the node Y-coordinate.
589: *
590: * @return int
591: *
592: * @since 1.0
593: */
594: public function getY()
595: {
596: return $this->y;
597: }
598:
599: /**
600: * Sets the node X-coordinate.
601: *
602: * @param int $x
603: *
604: * @since 1.0
605: */
606: public function setX($x)
607: {
608: $this->x = $x;
609: }
610:
611: /**
612: * Sets the node Y-coordinate.
613: *
614: * @param int $y
615: *
616: * @since 1.0
617: */
618: public function setY($y)
619: {
620: $this->y = $y;
621: }
622: }
623: