1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/misc/types_nl.h"
23 #include "nel/misc/hierarchical_timer.h"
24 #include "nel/ligo/primitive.h"
25 #include "nel/ligo/ligo_config.h"
26 #include "nel/ligo/primitive_class.h"
27 #include "nel/misc/i_xml.h"
28 #include "nel/misc/path.h"
30 using namespace NLMISC
;
33 const uint32 NLLIGO_PRIMITIVE_VERSION
= 1;
42 CPrimitiveContext
*CPrimitiveContext::_Instance
= NULL
;
45 // ***************************************************************************
47 // ***************************************************************************
49 void Error (const std::string
&filename
, const char *format
, ...)
52 va_start( args
, format
);
54 vsnprintf( buffer
, 1024, format
, args
);
57 nlwarning ("In File (%s) %s", filename
.c_str(), buffer
);
60 // ***************************************************************************
62 void XMLError (xmlNodePtr xmlNode
, const std::string
&filename
, const char *format
, ... )
65 va_start( args
, format
);
67 vsnprintf( buffer
, 1024, format
, args
);
70 Error (filename
, "node (%s), line (%d) : %s", xmlNode
->name
, xmlNode
->line
, buffer
);
74 // ***************************************************************************
76 xmlNodePtr
GetFirstChildNode (xmlNodePtr xmlNode
, const std::string
&filename
, const std::string
&childName
)
78 // Call the CIXml version
79 xmlNodePtr result
= CIXml::getFirstChildNode (xmlNode
, childName
);
80 if (result
) return result
;
82 // Output a formated error
83 XMLError (xmlNode
, filename
.c_str(), "Can't find XML node named (%s)", childName
.c_str());
87 // ***************************************************************************
89 bool GetPropertyString (string
&result
, const std::string
&filename
, xmlNodePtr xmlNode
, const std::string
&propName
)
91 // Call the CIXml version
92 if (!CIXml::getPropertyString (result
, xmlNode
, propName
))
94 // Output a formated error
95 XMLError (xmlNode
, filename
, "Can't find XML node property (%s)", propName
.c_str());
101 // ***************************************************************************
103 bool ReadInt (const std::string
&propName
, int &result
, const std::string
&filename
, xmlNodePtr xmlNode
)
106 if (GetPropertyString (value
, filename
, xmlNode
, propName
))
108 result
= atoi (value
.c_str ());
114 // ***************************************************************************
116 void WriteInt (const std::string
&propName
, int value
, xmlNodePtr xmlNode
)
119 xmlSetProp (xmlNode
, (const xmlChar
*)propName
.c_str(), (const xmlChar
*)(toString (value
).c_str ()));
122 // ***************************************************************************
124 bool ReadUInt (const std::string
&propName
, uint
&result
, const std::string
&filename
, xmlNodePtr xmlNode
)
127 if (GetPropertyString (value
, filename
, xmlNode
, propName
))
129 result
= strtoul (value
.c_str (), NULL
, 10);
135 // ***************************************************************************
137 void WriteUInt (const std::string
&propName
, uint value
, xmlNodePtr xmlNode
)
140 xmlSetProp (xmlNode
, (const xmlChar
*)propName
.c_str(), (const xmlChar
*)(toString (value
).c_str ()));
143 // ***************************************************************************
145 bool ReadFloat (const std::string
&propName
, float &result
, const std::string
&filename
, xmlNodePtr xmlNode
)
148 if (GetPropertyString (value
, filename
, xmlNode
, propName
))
150 NLMISC::fromString(value
, result
);
156 // ***************************************************************************
158 void WriteFloat (const std::string
&propName
, float value
, xmlNodePtr xmlNode
)
161 xmlSetProp (xmlNode
, (const xmlChar
*)propName
.c_str(), (const xmlChar
*)(toString (value
).c_str ()));
164 // ***************************************************************************
166 bool ReadVector (CPrimVector
&point
, const std::string
&filename
, xmlNodePtr xmlNode
)
169 if (ReadFloat ("X", pos
.x
, filename
, xmlNode
))
171 if (ReadFloat ("Y", pos
.y
, filename
, xmlNode
))
173 if (ReadFloat ("Z", pos
.z
, filename
, xmlNode
))
175 pos
.Selected
= false;
177 if (CIXml::getPropertyString (result
, xmlNode
, "SELECTED"))
179 if (result
== "true")
190 // ***************************************************************************
192 void WriteVector (const CPrimVector
&point
, xmlNodePtr xmlNode
)
195 xmlSetProp (xmlNode
, (const xmlChar
*)"X", (const xmlChar
*)(toString (point
.x
).c_str ()));
196 xmlSetProp (xmlNode
, (const xmlChar
*)"Y", (const xmlChar
*)(toString (point
.y
).c_str ()));
197 xmlSetProp (xmlNode
, (const xmlChar
*)"Z", (const xmlChar
*)(toString (point
.z
).c_str ()));
199 xmlSetProp (xmlNode
, (const xmlChar
*)"SELECTED", (const xmlChar
*)"true");
203 // ***************************************************************************
205 bool GetNodeString (string
&result
, const std::string
&filename
, xmlNodePtr xmlNode
, const std::string
&nodeName
)
208 xmlNodePtr node
= CIXml::getFirstChildNode (xmlNode
, nodeName
);
211 XMLError (xmlNode
, filename
, "Can't find XML node named (%s)", nodeName
.c_str());
215 // Get the node string
216 if (!CIXml::getContentString (result
, node
))
218 XMLError (xmlNode
, filename
, "Can't find any text in the node named (%s)", nodeName
.c_str());
225 // ***************************************************************************
227 bool GetContentString (string
&result
, const std::string
&filename
, xmlNodePtr xmlNode
)
229 // Get the node string
230 if (!CIXml::getContentString (result
, xmlNode
))
232 XMLError (xmlNode
, filename
, "Can't find any text in the node");
239 // ***************************************************************************
241 // ***************************************************************************
243 CPropertyString::CPropertyString (const std::string
&str
)
248 // ***************************************************************************
250 CPropertyString::CPropertyString (const std::string
&str
, bool _default
)
256 // ***************************************************************************
257 // CPropertyStringArray
258 // ***************************************************************************
260 CPropertyStringArray::CPropertyStringArray (const std::vector
<std::string
> &stringArray
)
262 StringArray
= stringArray
;
265 // ***************************************************************************
267 CPropertyStringArray::CPropertyStringArray (const std::vector
<std::string
> &stringArray
, bool _default
)
269 StringArray
= stringArray
;
273 // ***************************************************************************
275 void CPrimPoint::serial (NLMISC::IStream
&f
)
278 IPrimitive::serial(f
);
283 // ***************************************************************************
284 void CPrimPath::serial (NLMISC::IStream
&f
)
286 IPrimitive::serial(f
);
287 f
.serialCont(VPoints
);
290 // ***************************************************************************
292 bool CPrimZone::contains (const NLMISC::CVector
&v
, const std::vector
<CPrimVector
> &points
)
297 // Point or line can't contains !
298 if (points
.size() < 3)
301 // Get the bounding rectangle of the zone
302 vMax
= vMin
= points
[0];
303 for (i
= 0; i
< points
.size(); ++i
)
305 if (vMin
.x
> points
[i
].x
)
306 vMin
.x
= points
[i
].x
;
307 if (vMin
.y
> points
[i
].y
)
308 vMin
.y
= points
[i
].y
;
310 if (vMax
.x
< points
[i
].x
)
311 vMax
.x
= points
[i
].x
;
312 if (vMax
.y
< points
[i
].y
)
313 vMax
.y
= points
[i
].y
;
316 if ((v
.x
< vMin
.x
) || (v
.y
< vMin
.y
) || (v
.x
> vMax
.x
) || (v
.y
> vMax
.y
))
319 uint32 nNbIntersection
= 0;
320 for (i
= 0; i
< points
.size(); ++i
)
322 const CVector
&p1
= points
[i
];
323 const CVector
&p2
= points
[(i
+1)%points
.size()];
325 if (((p1
.y
-v
.y
) <= 0.0)&&((p2
.y
-v
.y
) <= 0.0))
327 if (((p1
.y
-v
.y
) > 0.0)&&((p2
.y
-v
.y
) > 0.0))
329 float xinter
= p1
.x
+ (p2
.x
-p1
.x
) * ((v
.y
-p1
.y
)/(p2
.y
-p1
.y
));
333 if ((nNbIntersection
&1) == 1) // odd intersections so the vertex is inside
339 // ***************************************************************************
341 bool CPrimZone::contains (const NLMISC::CVector
&v
, const std::vector
<NLMISC::CVector
> &points
)
346 // Point or line can't contains !
347 if (points
.size() < 3)
350 // Get the bounding rectangle of the zone
351 vMax
= vMin
= points
[0];
352 for (i
= 0; i
< points
.size(); ++i
)
354 if (vMin
.x
> points
[i
].x
)
355 vMin
.x
= points
[i
].x
;
356 if (vMin
.y
> points
[i
].y
)
357 vMin
.y
= points
[i
].y
;
359 if (vMax
.x
< points
[i
].x
)
360 vMax
.x
= points
[i
].x
;
361 if (vMax
.y
< points
[i
].y
)
362 vMax
.y
= points
[i
].y
;
365 if ((v
.x
< vMin
.x
) || (v
.y
< vMin
.y
) || (v
.x
> vMax
.x
) || (v
.y
> vMax
.y
))
368 uint32 nNbIntersection
= 0;
369 for (i
= 0; i
< points
.size(); ++i
)
371 const CVector
&p1
= points
[i
];
372 const CVector
&p2
= points
[(i
+1)%points
.size()];
374 if (((p1
.y
-v
.y
) <= 0.0)&&((p2
.y
-v
.y
) <= 0.0))
376 if (((p1
.y
-v
.y
) > 0.0)&&((p2
.y
-v
.y
) > 0.0))
378 float xinter
= p1
.x
+ (p2
.x
-p1
.x
) * ((v
.y
-p1
.y
)/(p2
.y
-p1
.y
));
382 if ((nNbIntersection
&1) == 1) // odd intersections so the vertex is inside
388 // ***************************************************************************
390 // ***************************************************************************
392 bool CPrimNode::read (xmlNodePtr xmlNode
, const std::string
&filename
, uint version
, CLigoConfig
&config
)
394 return IPrimitive::read (xmlNode
, filename
, version
, config
);
397 // ***************************************************************************
399 uint
CPrimNode::getNumVector () const
404 // ***************************************************************************
406 const CPrimVector
*CPrimNode::getPrimVector () const
411 // ***************************************************************************
413 CPrimVector
*CPrimNode::getPrimVector ()
418 // ***************************************************************************
420 NLLIGO::IPrimitive
*CPrimNode::copy () const
422 return new CPrimNode (*this);
426 // ***************************************************************************
428 // ***************************************************************************
430 /*void CPrimNode::operator= (const CPrimNode &node)
432 // Copy the IPrimitive
433 IPrimitive::operator= (node);
436 // ***************************************************************************
438 void CPrimPoint::operator= (const CPrimPoint &node)
440 // Copy the IPrimitive
441 IPrimitive::operator= (node);
444 // ***************************************************************************
446 void CPrimPath::operator= (const CPrimPath &node)
448 // Copy the IPrimitive
451 // ***************************************************************************
453 void CPrimZone::operator= (const CPrimZone &node)
455 // Copy the IPrimitive
456 IPrimitive::operator= (node);
460 // ***************************************************************************
462 uint
CPrimPoint::getNumVector () const
467 // ***************************************************************************
469 const CPrimVector
*CPrimPoint::getPrimVector () const
474 // ***************************************************************************
476 CPrimVector
*CPrimPoint::getPrimVector ()
481 // ***************************************************************************
483 NLLIGO::IPrimitive
*CPrimPoint::copy () const
485 return new CPrimPoint (*this);
488 // ***************************************************************************
490 bool CPrimPoint::read(xmlNodePtr xmlNode
, const std::string
&filename
, uint version
, CLigoConfig
&config
)
493 xmlNodePtr ptNode
= GetFirstChildNode (xmlNode
, filename
, "PT");
497 if (!ReadVector (Point
, filename
, ptNode
))
500 ptNode
= CIXml::getFirstChildNode (xmlNode
, "ANGLE");
504 if (!ReadFloat ("VALUE", Angle
, filename
, ptNode
))
515 return IPrimitive::read (xmlNode
, filename
, version
, config
);
518 // ***************************************************************************
520 void CPrimPoint::write (xmlNodePtr xmlNode
, const std::string
&filename
) const
523 xmlNodePtr ptNode
= xmlNewChild ( xmlNode
, NULL
, (const xmlChar
*)"PT", NULL
);
524 WriteVector (Point
, ptNode
);
529 xmlNodePtr ptNode
= xmlNewChild ( xmlNode
, NULL
, (const xmlChar
*)"ANGLE", NULL
);
530 WriteFloat ("VALUE", Angle
, ptNode
);
533 IPrimitive::write (xmlNode
, filename
);
536 // ***************************************************************************
538 // ***************************************************************************
540 uint
CPrimPath::getNumVector () const
542 return (uint
)VPoints
.size ();
545 // ***************************************************************************
547 const CPrimVector
*CPrimPath::getPrimVector () const
551 return &(VPoints
[0]);
554 // ***************************************************************************
556 NLLIGO::IPrimitive
*CPrimPath::copy () const
558 return new CPrimPath (*this);
561 // ***************************************************************************
563 CPrimVector
*CPrimPath::getPrimVector ()
567 return &(VPoints
[0]);
570 // ***************************************************************************
572 bool CPrimPath::read (xmlNodePtr xmlNode
, const std::string
&filename
, uint version
, CLigoConfig
&config
)
576 VPoints
.reserve (CIXml::countChildren (xmlNode
, "PT"));
577 xmlNodePtr ptNode
= CIXml::getFirstChildNode (xmlNode
, "PT");
583 VPoints
.push_back (CPrimVector ());
584 if (!ReadVector (VPoints
.back (), filename
, ptNode
))
587 ptNode
= CIXml::getNextChildNode (ptNode
, "PT");
592 return IPrimitive::read (xmlNode
, filename
, version
, config
);
595 // ***************************************************************************
597 void CPrimPath::write (xmlNodePtr xmlNode
, const std::string
&filename
) const
600 for (uint i
=0; i
<VPoints
.size (); i
++)
602 xmlNodePtr ptNode
= xmlNewChild ( xmlNode
, NULL
, (const xmlChar
*)"PT", NULL
);
603 WriteVector (VPoints
[i
], ptNode
);
606 IPrimitive::write (xmlNode
, filename
);
609 // ***************************************************************************
611 // ***************************************************************************
613 uint
CPrimZone::getNumVector () const
615 return (uint
)VPoints
.size ();
618 // ***************************************************************************
620 const CPrimVector
*CPrimZone::getPrimVector () const
624 return &(VPoints
[0]);
627 // ***************************************************************************
629 NLLIGO::IPrimitive
*CPrimZone::copy () const
631 return new CPrimZone (*this);
634 // ***************************************************************************
636 CPrimVector
*CPrimZone::getPrimVector ()
638 if(VPoints
.empty()) return 0;
639 return &(VPoints
[0]);
642 // ***************************************************************************
644 bool CPrimZone::read (xmlNodePtr xmlNode
, const std::string
&filename
, uint version
, CLigoConfig
&config
)
648 VPoints
.reserve (CIXml::countChildren (xmlNode
, "PT"));
649 xmlNodePtr ptNode
= CIXml::getFirstChildNode (xmlNode
, "PT");
655 VPoints
.push_back (CPrimVector ());
656 if (!ReadVector (VPoints
.back (), filename
, ptNode
))
659 ptNode
= CIXml::getNextChildNode (ptNode
, "PT");
664 return IPrimitive::read (xmlNode
, filename
, version
, config
);
667 // ***************************************************************************
669 void CPrimZone::write (xmlNodePtr xmlNode
, const std::string
&filename
) const
672 for (uint i
=0; i
<VPoints
.size (); i
++)
674 xmlNodePtr ptNode
= xmlNewChild ( xmlNode
, NULL
, (const xmlChar
*)"PT", NULL
);
675 WriteVector (VPoints
[i
], ptNode
);
678 IPrimitive::write (xmlNode
, filename
);
681 // ***************************************************************************
683 bool CPrimZone::contains (const NLMISC::CVector
&v
, const std::vector
<CPrimVector
> &points
, float &distance
, NLMISC::CVector
&nearPos
, bool isPath
)
685 H_AUTO(NLLIGO_Contains1
)
688 float nearest
= FLT_MAX
;
691 // Point or line can't contains !
692 if (points
.size() < 3 || isPath
)
694 // only compute the distance.
695 if (points
.size() == 1)
697 distance
= (points
[0] - v
).norm();
700 else if (points
.size() == 2)
702 distance
= getSegmentDist(v
, points
[0], points
[1], nearPos
);
706 // compute nearest segment
707 for (i
= 0; i
< points
.size()-1; ++i
)
709 const CVector
&p1
= points
[i
];
710 const CVector
&p2
= points
[i
+1];
712 float dist
= getSegmentDist(v
, p1
, p2
, pos
);
724 // Get the bounding rectangle of the zone
725 vMax
= vMin
= points
[0];
726 for (i
= 0; i
< points
.size(); ++i
)
728 vMin
.x
= min(vMin
.x
, points
[i
].x
);
729 vMin
.y
= min(vMin
.y
, points
[i
].y
);
730 vMax
.x
= max(vMax
.x
, points
[i
].x
);
731 vMax
.y
= max(vMax
.y
, points
[i
].y
);
734 if ((v
.x
< vMin
.x
) || (v
.y
< vMin
.y
) || (v
.x
> vMax
.x
) || (v
.y
> vMax
.y
))
736 // find the nearest distance of all segment
737 for (uint i
=0; i
<points
.size(); ++i
)
739 float dist
= getSegmentDist(v
, points
[i
], points
[(i
+1) % points
.size()], pos
);
751 uint32 nNbIntersection
= 0;
752 for (i
= 0; i
< points
.size(); ++i
)
754 const CVector
&p1
= points
[i
];
755 const CVector
&p2
= points
[(i
+1)%points
.size()];
757 float dist
= getSegmentDist(v
, p1
, p2
, pos
);
764 if (((p1
.y
-v
.y
) <= 0.0)&&((p2
.y
-v
.y
) <= 0.0))
766 if (((p1
.y
-v
.y
) > 0.0)&&((p2
.y
-v
.y
) > 0.0))
768 float xinter
= p1
.x
+ (p2
.x
-p1
.x
) * ((v
.y
-p1
.y
)/(p2
.y
-p1
.y
));
774 if ((nNbIntersection
&1) == 1) // odd intersections so the vertex is inside
780 // ***************************************************************************
782 bool CPrimZone::contains (const NLMISC::CVector
&v
, const std::vector
<CVector
> &points
, float &distance
, NLMISC::CVector
&nearPos
, bool isPath
)
784 H_AUTO(NLLIGO_Contains2
)
787 float nearest
= FLT_MAX
;
790 // Point or line can't contains !
791 if (points
.size() < 3 || isPath
)
793 // only compute the distance.
794 if (points
.size() == 1)
796 distance
= (points
[0] - v
).norm();
799 else if (points
.size() == 2)
801 distance
= getSegmentDist(v
, points
[0], points
[1], nearPos
);
805 // compute nearest segment
806 for (i
= 0; i
< points
.size()-1; ++i
)
808 const CVector
&p1
= points
[i
];
809 const CVector
&p2
= points
[i
+1];
811 float dist
= getSegmentDist(v
, p1
, p2
, pos
);
823 // Get the bounding rectangle of the zone
824 vMax
= vMin
= points
[0];
825 for (i
= 0; i
< points
.size(); ++i
)
827 vMin
.x
= min(vMin
.x
, points
[i
].x
);
828 vMin
.y
= min(vMin
.y
, points
[i
].y
);
829 vMax
.x
= max(vMax
.x
, points
[i
].x
);
830 vMax
.y
= max(vMax
.y
, points
[i
].y
);
833 if ((v
.x
< vMin
.x
) || (v
.y
< vMin
.y
) || (v
.x
> vMax
.x
) || (v
.y
> vMax
.y
))
835 // find the nearest distance of all segment
836 for (uint i
=0; i
<points
.size(); ++i
)
838 float dist
= getSegmentDist(v
, points
[i
], points
[(i
+1) % points
.size()], pos
);
850 uint32 nNbIntersection
= 0;
851 for (i
= 0; i
< points
.size(); ++i
)
853 const CVector
&p1
= points
[i
];
854 const CVector
&p2
= points
[(i
+1)%points
.size()];
856 float dist
= getSegmentDist(v
, p1
, p2
, pos
);
863 if (((p1
.y
-v
.y
) <= 0.0)&&((p2
.y
-v
.y
) <= 0.0))
865 if (((p1
.y
-v
.y
) > 0.0)&&((p2
.y
-v
.y
) > 0.0))
867 float xinter
= p1
.x
+ (p2
.x
-p1
.x
) * ((v
.y
-p1
.y
)/(p2
.y
-p1
.y
));
873 if ((nNbIntersection
&1) == 1) // odd intersections so the vertex is inside
879 // ***************************************************************************
881 float CPrimZone::getSegmentDist(const NLMISC::CVector v
, const NLMISC::CVector
&p1
, const NLMISC::CVector
&p2
, NLMISC::CVector
&nearPos
)
883 // two points, compute distance to the segment.
884 CVector V
= (p2
-p1
).normed();
885 double length
= (p2
-p1
).norm();
892 distance
= (p1
-v
).norm();
897 float t
= (float)((double)((v
-p1
)*V
)/length
);
901 distance
= (p1
-v
).norm();
906 distance
= (p2
-v
).norm();
910 nearPos
= p1
+ t
*(p2
-p1
);
911 distance
= (v
-nearPos
).norm();
919 // ***************************************************************************
920 NLMISC::CVector
CPrimZone::getBarycentre() const
922 CVector
sum( CVector::Null
);
923 uint n
= (uint
)VPoints
.size();
926 for ( uint i
=0; i
!=n
; ++i
)
928 return sum
/ (float)n
;
934 // ***************************************************************************
935 void CPrimZone::getAABox( NLMISC::CVector
& cornerMin
, NLMISC::CVector
& cornerMax
) const
937 cornerMin
.x
= FLT_MAX
;
938 cornerMin
.y
= FLT_MAX
;
940 cornerMax
.x
= -FLT_MAX
;
941 cornerMax
.y
= -FLT_MAX
;
943 for ( uint i
=0; i
!=VPoints
.size(); ++i
)
945 const CVector
& p
= VPoints
[i
];
946 if ( p
.x
< cornerMin
.x
)
948 if ( p
.x
> cornerMax
.x
)
950 if ( p
.y
< cornerMin
.y
)
952 if ( p
.y
> cornerMax
.y
)
958 // ***************************************************************************
959 float CPrimZone::getAreaOfAABox() const
961 CVector cornerMin
, cornerMax
;
962 getAABox( cornerMin
, cornerMax
);
963 return (cornerMax
.x
-cornerMin
.x
) * (cornerMax
.y
-cornerMin
.y
);
967 // ***************************************************************************
968 void CPrimZone::serial (NLMISC::IStream
&f
)
970 IPrimitive::serial(f
);
971 f
.serialCont(VPoints
);
974 // ***************************************************************************
975 void CPrimRegion::serial (NLMISC::IStream
&f
)
977 f
.xmlPushBegin ("REGION");
979 f
.xmlSetAttrib ("NAME");
985 version
= f
.serialVersion (version
);
986 string check
= "REGION";
987 f
.serialCheck (check
);
989 f
.xmlPush ("POINTS");
990 f
.serialCont (VPoints
);
992 f
.xmlPush ("PATHES");
993 f
.serialCont (VPaths
);
996 f
.serialCont (VZones
);
1001 f
.xmlPush ("HIDEPOINTS");
1002 f
.serialCont (VHidePoints
);
1004 f
.xmlPush ("HIDEZONES");
1005 f
.serialCont (VHideZones
);
1007 f
.xmlPush ("HIDEPATHS");
1008 f
.serialCont (VHidePaths
);
1013 VHidePoints
.resize (VPoints
.size(), false);
1014 VHideZones
.resize (VZones
.size(), false);
1015 VHidePaths
.resize (VPaths
.size(), false);
1019 // ***************************************************************************
1021 // ***************************************************************************
1023 IPrimitive::IPrimitive ()
1029 IPrimitive::IPrimitive (const IPrimitive
&node
) : IStreamable()
1032 IPrimitive::operator= (node
);
1035 // ***************************************************************************
1037 void IPrimitive::serial (NLMISC::IStream
&f
)
1039 // NB : unparsed parameters are not binary serialized !
1041 // serialize the property container
1046 for (uint i
=0; i
<size
; ++i
)
1050 IProperty
*&pp
= _Properties
[s
];
1051 f
.serialPolyPtr(pp
);
1056 uint32 size
= (uint32
)_Properties
.size();
1058 std::map
<std::string
, IProperty
*>::iterator
first(_Properties
.begin()), last(_Properties
.end());
1059 for (; first
!= last
; ++first
)
1061 std::string
&s
= const_cast<std::string
&>(first
->first
);
1064 f
.serialPolyPtr(first
->second
);
1071 // f.serial(Expanded);
1073 // serial the childrens
1076 std::vector
<IPrimitive
*> children
;
1077 f
.serialContPolyPtr(children
);
1079 for(std::vector
<IPrimitive
*>::iterator it
= children
.begin(); it
!= children
.end(); ++it
, ++index
)
1081 insertChild(*it
, index
);
1086 f
.serialContPolyPtr(_Children
);
1092 vector
<IPrimitive
*>::iterator
first(_Children
.begin()), last(_Children
.end());
1093 for (; first
!= last
; ++first
)
1096 (*first
)->_Parent
= this;
1102 // ***************************************************************************
1104 void IPrimitive::updateChildId (uint index
)
1107 uint count
= (uint
)_Children
.size ();
1108 for (i
=index
; i
<count
; i
++)
1109 _Children
[i
]->_ChildId
= i
;
1112 // ***************************************************************************
1114 void IPrimitive::branchLink()
1117 std::vector
<IPrimitive
*>::iterator
first(_Children
.begin()), last(_Children
.end());
1118 for (; first
!= last
; ++first
)
1120 (*first
)->branchLink();
1124 // ***************************************************************************
1126 void IPrimitive::branchUnlink()
1129 std::vector
<IPrimitive
*>::iterator
first(_Children
.begin()), last(_Children
.end());
1130 for (; first
!= last
; ++first
)
1132 (*first
)->branchUnlink();
1137 // ***************************************************************************
1139 void IPrimitive::operator= (const IPrimitive
&node
)
1143 removeProperties ();
1145 // copy deprecated param
1146 // Layer = node.Layer;
1147 // Name = node.Name;
1149 // copy unparsed properties
1150 _UnparsedProperties
= node
._UnparsedProperties
;
1153 // Expanded = node.Expanded;
1154 _ChildId
= node
._ChildId
;
1157 _Children
.resize (node
._Children
.size ());
1158 for (uint child
= 0; child
< node
._Children
.size (); child
++)
1161 _Children
[child
] = node
._Children
[child
]->copy ();
1164 _Children
[child
]->_Parent
= this;
1168 std::map
<std::string
, IProperty
*>::const_iterator ite
= node
._Properties
.begin ();
1169 while (ite
!= node
._Properties
.end ())
1172 CPropertyString
*propString
= dynamic_cast<CPropertyString
*>(ite
->second
);
1176 CPropertyString
*newProp
= new CPropertyString ();
1177 *newProp
= *propString
;
1178 _Properties
.insert (std::map
<std::string
, IProperty
*>::value_type (ite
->first
, newProp
));
1182 CPropertyStringArray
*propStringArray
= dynamic_cast<CPropertyStringArray
*>(ite
->second
);
1183 if (propStringArray
)
1186 CPropertyStringArray
*newProp
= new CPropertyStringArray ();
1187 *newProp
= *propStringArray
;
1188 _Properties
.insert (std::map
<std::string
, IProperty
*>::value_type (ite
->first
, newProp
));
1192 CPropertyColor
*propColor
= dynamic_cast<CPropertyColor
*>(ite
->second
);
1193 nlverify (propColor
);
1196 CPropertyColor
*newProp
= new CPropertyColor ();
1197 *newProp
= *propColor
;
1198 _Properties
.insert (std::map
<std::string
, IProperty
*>::value_type (ite
->first
, newProp
));
1206 _DebugClassName
= node
._DebugClassName
;
1207 _DebugPrimitiveName
= node
._DebugPrimitiveName
;
1212 const IPrimitive
*IPrimitive::getPrimitive (const std::string
&absoluteOrRelativePath
) const
1214 const IPrimitive
*cursor
=this;
1215 string path
=absoluteOrRelativePath
;
1217 if (path
.find("//")==0) // an absolute path.
1219 while (cursor
->getParent())
1220 cursor
=cursor
->getParent();
1224 while (!path
.empty())
1226 if (path
.find("/")==0)
1231 if (path
.find("..")==0)
1233 cursor
=cursor
->getParent();
1241 string::size_type indexStr
=path
.find("/");
1243 if (indexStr
==string::npos
)
1250 childName
=path
.substr(0,indexStr
);
1251 path
.erase(0, indexStr
);
1253 childName
=toUpperAscii(childName
);
1254 const IPrimitive
*child
=NULL
;
1256 for (childIndex
=0;childIndex
<cursor
->getNumChildren();childIndex
++)
1258 cursor
->getChild(child
,childIndex
);
1261 if ( child
->getPropertyByName("class", name
)
1262 && toUpperAscii(name
)==childName
)
1265 if (childIndex
>=cursor
->getNumChildren())
1273 // ***************************************************************************
1275 bool IPrimitive::getProperty (uint index
, std::string
&property_name
, const IProperty
*&result
) const
1277 // Look for the property
1278 std::map
<std::string
, IProperty
*>::const_iterator ite
= _Properties
.begin ();
1279 while (ite
!= _Properties
.end ())
1283 property_name
= ite
->first
;
1284 result
= ite
->second
;
1290 nlwarning ("NLLIGO::IPrimitive::getProperty : invalid index (index : %u, size : %u).", index
, (uint
)_Properties
.size ());
1294 // ***************************************************************************
1296 bool IPrimitive::getProperty (uint index
, std::string
&property_name
, IProperty
*&result
)
1298 // Look for the property
1299 std::map
<std::string
, IProperty
*>::iterator ite
= _Properties
.begin ();
1300 while (ite
!= _Properties
.end ())
1304 property_name
= ite
->first
;
1305 result
= ite
->second
;
1311 nlwarning ("NLLIGO::IPrimitive::getProperty : invalid index (index : %u, size : %u).", index
, (uint
)_Properties
.size ());
1315 // ***************************************************************************
1317 bool IPrimitive::getPropertyByName (const std::string
&property_name
, const IProperty
*&result
) const
1319 // Look for the property
1320 std::map
<std::string
, IProperty
*>::const_iterator ite
= _Properties
.find (property_name
);
1321 if (ite
!= _Properties
.end ())
1323 result
= ite
->second
;
1329 // ***************************************************************************
1331 bool IPrimitive::getPropertyByName (const std::string
&property_name
, IProperty
*&result
) const
1333 // Look for the property
1334 std::map
<std::string
, IProperty
*>::const_iterator ite
= _Properties
.find (property_name
);
1335 if (ite
!= _Properties
.end ())
1337 result
= ite
->second
;
1343 // ***************************************************************************
1345 bool IPrimitive::getPropertyByName (const std::string
&property_name
, std::string
*&result
) const
1349 if (getPropertyByName (property_name
, prop
))
1351 CPropertyString
*strProp
= dynamic_cast<CPropertyString
*> (prop
);
1354 result
= &(strProp
->String
);
1359 nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name
.c_str());
1365 // ***************************************************************************
1367 bool IPrimitive::getPropertyByName (const std::string
&property_name
, std::string
&result
) const
1370 const IProperty
*prop
;
1371 if (getPropertyByName (property_name
, prop
))
1373 const CPropertyString
*strProp
= dynamic_cast<const CPropertyString
*> (prop
);
1376 result
= strProp
->String
;
1381 nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name
.c_str());
1387 // ***************************************************************************
1389 bool IPrimitive::getPropertyByName (const std::string
&property_name
, std::vector
<std::string
> *&result
) const
1393 if (getPropertyByName (property_name
, prop
))
1395 CPropertyStringArray
*strProp
= dynamic_cast<CPropertyStringArray
*> (prop
);
1398 result
= &(strProp
->StringArray
);
1403 nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name
.c_str());
1409 // ***************************************************************************
1411 bool IPrimitive::getPropertyByName (const std::string
&property_name
, const std::vector
<std::string
> *&result
) const
1415 if (getPropertyByName (property_name
, prop
))
1417 const CPropertyStringArray
*strProp
= dynamic_cast<const CPropertyStringArray
*> (prop
);
1420 result
= &(strProp
->StringArray
);
1425 nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name
.c_str());
1431 // ***************************************************************************
1433 bool IPrimitive::getPropertyByName (const std::string
&property_name
, NLMISC::CRGBA
&result
) const
1437 if (getPropertyByName (property_name
, prop
))
1439 const CPropertyColor
*colorProp
= dynamic_cast<const CPropertyColor
*> (prop
);
1442 result
= colorProp
->Color
;
1447 nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a color.", property_name
.c_str());
1453 // ***************************************************************************
1455 bool IPrimitive::removeProperty (uint index
)
1457 // Look for the property
1458 std::map
<std::string
, IProperty
*>::iterator ite
= _Properties
.begin ();
1459 while (ite
!= _Properties
.end ())
1463 _Properties
.erase (ite
);
1469 nlwarning ("NLLIGO::IPrimitive::removeProperty : invalid index (index : %u, size : %u).", index
, (uint
)_Properties
.size ());
1473 // ***************************************************************************
1475 bool IPrimitive::removePropertyByName (const std::string
&property_name
)
1477 // Look for the property
1478 std::map
<std::string
, IProperty
*>::iterator ite
= _Properties
.find (property_name
);
1479 if (ite
!= _Properties
.end ())
1481 _Properties
.erase (ite
);
1487 // ***************************************************************************
1489 void IPrimitive::removeProperties ()
1491 std::map
<std::string
, IProperty
*>::iterator ite
= _Properties
.begin ();
1492 while (ite
!= _Properties
.end ())
1497 _Properties
.clear ();
1500 // ***************************************************************************
1502 bool IPrimitive::getChild (const IPrimitive
*&result
, uint childId
) const
1504 if (childId
< _Children
.size ())
1506 result
= _Children
[childId
];
1511 nlwarning ("NLLIGO::IPrimitive::getChild : invalid index (index : %u, size %u).", childId
, (uint
)_Children
.size ());
1516 // ***************************************************************************
1518 bool IPrimitive::getChild (IPrimitive
*&result
, uint childId
)
1520 if (childId
< _Children
.size ())
1522 result
= _Children
[childId
];
1527 nlwarning ("NLLIGO::IPrimitive::getChild : invalid index (index : %u, size %u).", childId
, (uint
)_Children
.size ());
1532 // ***************************************************************************
1534 bool IPrimitive::removeChild (IPrimitive
*child
)
1537 if (getChildId(childId
, child
))
1539 return removeChild(childId
);
1543 nlwarning("NLLIGO::IPrimitive::removeChild : invalid child, can't remove (child : %p)", child
);
1548 // ***************************************************************************
1550 bool IPrimitive::removeChild (uint childId
)
1552 if (childId
< _Children
.size ())
1554 delete _Children
[childId
];
1555 _Children
.erase (_Children
.begin()+childId
);
1556 updateChildId (childId
);
1561 nlwarning ("NLLIGO::IPrimitive::removeChild : invalid index (index : %u, size %u).", childId
, (uint
)_Children
.size ());
1566 // ***************************************************************************
1568 void IPrimitive::removeChildren ()
1571 for (uint i
=0; i
<_Children
.size (); i
++)
1573 delete _Children
[i
];
1578 // ***************************************************************************
1580 bool IPrimitive::unlinkChild(IPrimitive
*child
)
1583 if (getChildId(childId
, child
))
1585 child
->onUnlinkFromParent();
1586 child
->branchUnlink();
1587 _Children
.erase (_Children
.begin()+childId
);
1588 updateChildId (childId
);
1589 child
->_Parent
= NULL
;
1590 child
->_ChildId
= 0;
1595 nlwarning("NLLIGO::IPrimitive::unlinkChild : invalid child, can't unlink (child : %p)", child
);
1600 // ***************************************************************************
1602 bool IPrimitive::insertChild (IPrimitive
*primitive
, uint index
)
1605 if (index
== AtTheEnd
)
1606 index
= (uint
)_Children
.size ();
1609 if (index
>_Children
.size ())
1613 _Children
.insert (_Children
.begin () + index
, primitive
);
1616 updateChildId (index
);
1618 // Link to the parent
1619 primitive
->_Parent
= this;
1622 primitive
->onLinkToParent();
1623 primitive
->branchLink();
1628 // ***************************************************************************
1630 IPrimitive::~IPrimitive ()
1636 removeProperties ();
1639 // ***************************************************************************
1640 bool IPrimitive::checkProperty(const std::string
&property_name
) const
1642 if (_Properties
.find(property_name
) == _Properties
.end())
1647 // ***************************************************************************
1649 bool IPrimitive::addPropertyByName (const std::string
&property_name
, IProperty
*result
)
1651 bool inserted
= _Properties
.insert (std::map
<std::string
, IProperty
*>::value_type (property_name
, result
)).second
;
1659 // ***************************************************************************
1661 bool IPrimitive::read (xmlNodePtr xmlNode
, const std::string
&filename
, uint version
, CLigoConfig
&config
)
1663 // Erase old properties
1664 _Properties
.clear ();
1666 // Read the unparsed properties (for editor view)
1667 xmlNodePtr commentNode
= CIXml::getFirstChildNode(xmlNode
, XML_COMMENT_NODE
);
1670 if (!CIXml::getContentString(_UnparsedProperties
, commentNode
))
1671 _UnparsedProperties
.clear();
1674 // Read the expanded flag
1677 // if (CIXml::getPropertyString (expanded, xmlNode, "EXPANDED"))
1678 // Expanded = (expanded != "false");
1680 // Read the properties
1681 xmlNodePtr propNode
;
1682 propNode
= CIXml::getFirstChildNode (xmlNode
, "PROPERTY");
1689 if (GetNodeString (name
, filename
, propNode
, "NAME"))
1691 // Get the property type
1693 if (GetPropertyString (type
, filename
, propNode
, "TYPE"))
1696 IProperty
*property
= NULL
;
1699 if (type
== "string")
1701 // Create a new property
1702 CPropertyString
*propertyString
= new CPropertyString
;
1703 property
= propertyString
;
1706 if (!GetNodeString (propertyString
->String
, filename
, propNode
, "STRING"))
1711 else if (type
== "string_array")
1713 // Create a new property
1714 CPropertyStringArray
*propertyStringArray
= new CPropertyStringArray
;
1715 property
= propertyStringArray
;
1718 xmlNodePtr stringNode
;
1719 propertyStringArray
->StringArray
.reserve (CIXml::countChildren (propNode
, "STRING"));
1720 stringNode
= CIXml::getFirstChildNode (propNode
, "STRING");
1727 GetContentString (content
, filename
, stringNode
);
1728 propertyStringArray
->StringArray
.push_back (content
);
1730 stringNode
= CIXml::getNextChildNode (stringNode
, "STRING");
1735 else if (type
== "color")
1737 // Create a new property
1738 CPropertyColor
*propertyColor
= new CPropertyColor
;
1739 property
= propertyColor
;
1742 xmlNodePtr colorNode
;
1743 colorNode
= CIXml::getFirstChildNode (xmlNode
, "COLOR");
1745 if (GetPropertyString (R
, filename
, colorNode
, "R") &&
1746 GetPropertyString (G
, filename
, colorNode
, "G") &&
1747 GetPropertyString (B
, filename
, colorNode
, "B") &&
1748 GetPropertyString (A
, filename
, colorNode
, "A"))
1750 sint32 sR
=0, sG
=0, sB
=0, sA
=255;
1751 sR
= atoi (R
.c_str ());
1753 sG
= atoi (G
.c_str ());
1755 sB
= atoi (B
.c_str ());
1757 sA
= atoi (A
.c_str ());
1759 propertyColor
->Color
.R
= (uint8
)sR
;
1760 propertyColor
->Color
.G
= (uint8
)sG
;
1761 propertyColor
->Color
.B
= (uint8
)sB
;
1762 propertyColor
->Color
.A
= (uint8
)sA
;
1769 if (property
== NULL
)
1771 XMLError (propNode
, filename
, "IPrimitive::read : Unknown property type (%s)", type
.c_str ());
1776 _Properties
.insert (std::map
<std::string
, IProperty
*>::value_type (name
, property
));
1788 propNode
= CIXml::getNextChildNode (propNode
, "PROPERTY");
1793 // Initialise default value
1794 initDefaultValues (config
);
1797 xmlNodePtr childNode
;
1798 childNode
= CIXml::getFirstChildNode (xmlNode
, "CHILD");
1803 // Get the property class
1805 if (GetPropertyString (type
, filename
, childNode
, "TYPE"))
1818 IPrimitive
*primitive
= static_cast<IPrimitive
*> (CClassRegistry::create (type
));
1820 // Primitive type not found ?
1821 if (primitive
== NULL
)
1823 XMLError (childNode
, filename
, "IPrimitive::read : Unknown primitive type (%s)", type
.c_str ());
1828 primitive
->read (childNode
, filename
, version
, config
);
1831 insertChild (primitive
);
1839 childNode
= CIXml::getNextChildNode (childNode
, "CHILD");
1846 getPropertyByName("class", _DebugClassName
);
1847 getPropertyByName("name", _DebugPrimitiveName
);
1853 // ***************************************************************************
1855 void IPrimitive::initDefaultValues (CLigoConfig
&config
)
1857 // Get the primitive class
1858 const CPrimitiveClass
*primitiveClass
= config
.getPrimitiveClass (*this);
1861 // For each properties
1862 uint count
= (uint
)primitiveClass
->Parameters
.size ();
1864 for (i
=0; i
<count
; i
++)
1866 const CPrimitiveClass::CParameter
¶meter
= primitiveClass
->Parameters
[i
];
1870 if (!getPropertyByName (parameter
.Name
.c_str(), result
))
1872 // Create the property
1873 if ((parameter
.Type
== CPrimitiveClass::CParameter::StringArray
) || (parameter
.Type
== CPrimitiveClass::CParameter::ConstStringArray
))
1874 result
= new CPropertyStringArray();
1876 result
= new CPropertyString();
1877 nlverify (addPropertyByName (parameter
.Name
.c_str(), result
));
1881 // Set the default values
1882 for (i
=0; i
<count
; i
++)
1884 const CPrimitiveClass::CParameter
¶meter
= primitiveClass
->Parameters
[i
];
1886 CPropertyString
*pString
= NULL
;
1887 CPropertyStringArray
*pStringArray
= NULL
;
1890 nlverify (getPropertyByName (parameter
.Name
.c_str(), result
));
1891 pString
= dynamic_cast<CPropertyString
*>(result
);
1893 pStringArray
= dynamic_cast<CPropertyStringArray
*>(result
);
1895 // Property have default values ?
1899 if (pString
->String
.empty())
1902 pString
->Default
= true;
1903 parameter
.getDefaultValue (pString
->String
, *this, *primitiveClass
);
1906 else if (pStringArray
)
1908 // Empty string array ?
1909 if (pStringArray
->StringArray
.empty())
1912 pStringArray
->Default
= true;
1913 parameter
.getDefaultValue (pStringArray
->StringArray
, *this, *primitiveClass
);
1920 // ***************************************************************************
1922 void IPrimitive::write (xmlNodePtr xmlNode
, const std::string
&filename
) const
1924 // Save the expanded flag
1926 // xmlSetProp (xmlNode, (const xmlChar*)"EXPANDED", (const xmlChar*)"false");
1929 xmlSetProp (xmlNode
, (const xmlChar
*)"TYPE", (const xmlChar
*)(const_cast<IPrimitive
*> (this)->getClassName ().c_str ()));
1931 // Save the unparsed property
1932 if (!_UnparsedProperties
.empty())
1934 xmlNodePtr commentNode
= xmlNewComment((const xmlChar
*)(_UnparsedProperties
.c_str()));
1935 nlverify(commentNode
);
1936 xmlAddChild(xmlNode
, commentNode
);
1939 // Save the properties
1940 std::map
<std::string
, IProperty
*>::const_iterator ite
= _Properties
.begin ();
1941 while (ite
!= _Properties
.end ())
1943 // Not a default property ?
1944 if (!ite
->second
->Default
)
1947 xmlNodePtr propNode
= xmlNewChild ( xmlNode
, NULL
, (const xmlChar
*)"PROPERTY", NULL
);
1948 xmlNodePtr nameNode
= xmlNewChild ( propNode
, NULL
, (const xmlChar
*)"NAME", NULL
);
1949 xmlNodePtr textNode
= xmlNewText ((const xmlChar
*)(ite
->first
.c_str ()));
1950 xmlAddChild (nameNode
, textNode
);
1953 const CPropertyString
*str
= dynamic_cast<const CPropertyString
*> (ite
->second
);
1957 xmlSetProp (propNode
, (const xmlChar
*)"TYPE", (const xmlChar
*)"string");
1960 xmlNodePtr stringNode
= xmlNewChild ( propNode
, NULL
, (const xmlChar
*)"STRING", NULL
);
1961 xmlNodePtr textNode
= xmlNewText ((const xmlChar
*)(str
->String
.c_str ()));
1962 xmlAddChild (stringNode
, textNode
);
1966 // Should be an array
1967 const CPropertyStringArray
*array
= dynamic_cast<const CPropertyStringArray
*> (ite
->second
);
1971 xmlSetProp (propNode
, (const xmlChar
*)"TYPE", (const xmlChar
*)"string_array");
1973 // For each strings in the array
1974 for (uint i
=0; i
<array
->StringArray
.size (); i
++)
1977 xmlNodePtr stringNode
= xmlNewChild ( propNode
, NULL
, (const xmlChar
*)"STRING", NULL
);
1978 xmlNodePtr textNode
= xmlNewText ((const xmlChar
*)(array
->StringArray
[i
].c_str ()));
1979 xmlAddChild (stringNode
, textNode
);
1984 // Should be a color
1985 const CPropertyColor
*color
= safe_cast
<const CPropertyColor
*> (ite
->second
);
1988 xmlSetProp (propNode
, (const xmlChar
*)"TYPE", (const xmlChar
*)"color");
1991 xmlNodePtr colorNode
= xmlNewChild ( propNode
, NULL
, (const xmlChar
*)"COLOR", NULL
);
1992 xmlSetProp (colorNode
, (const xmlChar
*)"R", (const xmlChar
*)toString (color
->Color
.R
).c_str ());
1993 xmlSetProp (colorNode
, (const xmlChar
*)"G", (const xmlChar
*)toString (color
->Color
.G
).c_str ());
1994 xmlSetProp (colorNode
, (const xmlChar
*)"B", (const xmlChar
*)toString (color
->Color
.B
).c_str ());
1995 xmlSetProp (colorNode
, (const xmlChar
*)"A", (const xmlChar
*)toString (color
->Color
.A
).c_str ());
2003 // Save the children
2004 for (uint i
=0; i
<_Children
.size (); i
++)
2007 xmlNodePtr childNode
= xmlNewChild ( xmlNode
, NULL
, (const xmlChar
*)"CHILD", NULL
);
2010 _Children
[i
]->write (childNode
, filename
);
2014 // ***************************************************************************
2016 bool IPrimitive::getChildId (uint
&childId
, const IPrimitive
*child
) const
2018 childId
= child
->_ChildId
;
2022 // ***************************************************************************
2024 uint
IPrimitive::getNumProperty () const
2026 return (uint
)_Properties
.size ();
2029 // ***************************************************************************
2031 std::string
IPrimitive::getName() const
2034 getPropertyByName("name", ret
);
2038 // ***************************************************************************
2040 const std::string
&IPrimitive::getUnparsedProperties() const
2042 return _UnparsedProperties
;
2045 // ***************************************************************************
2047 void IPrimitive::setUnparsedProperties(const std::string
&unparsedProperties
) const
2049 _UnparsedProperties
= unparsedProperties
;
2052 // ***************************************************************************
2054 // ***************************************************************************
2056 CPrimAlias::CPrimAlias() :
2062 CPrimAlias::CPrimAlias(const CPrimAlias
&other
)
2065 // clear the container reference and alias
2067 _Alias
= other
._Alias
;
2070 CPrimAlias::~CPrimAlias()
2076 void CPrimAlias::onBranchLink()
2078 CPrimitiveContext
&ctx
= CPrimitiveContext::instance();
2079 // context must be set when handling alias
2080 nlassert(ctx
.CurrentPrimitive
);
2081 nlassert(_Container
== NULL
|| _Container
== ctx
.CurrentPrimitive
);
2083 _Container
= ctx
.CurrentPrimitive
;
2085 // generate a new alias, eventually keeping the current one if any and if still available
2086 _Alias
= _Container
->genAlias(this, _Alias
);
2089 void CPrimAlias::onBranchUnlink()
2091 nlassert(_Container
!= NULL
);
2092 _Container
->releaseAlias(this, _Alias
);
2095 // NB : we keep the alias value for next linkage
2098 uint32
CPrimAlias::getAlias() const
2103 uint32
CPrimAlias::getFullAlias() const
2105 nlassert(_Container
!= NULL
);
2106 return _Container
->buildFullAlias(_Alias
);
2109 void CPrimAlias::regenAlias()
2111 // container must exist
2112 nlassert(_Container
);
2113 // generate a new alias, eventually keeping the current one if any and if still available
2114 _Alias
= _Container
->genAlias(this, _Alias
);
2118 // Read the primitive
2119 bool CPrimAlias::read (xmlNodePtr xmlNode
, const std::string
&filename
, uint version
, CLigoConfig
&config
)
2122 xmlNodePtr ptNode
= CIXml::getFirstChildNode (xmlNode
, "ALIAS");
2126 if (ReadInt ("VALUE", val
, filename
, ptNode
))
2128 _Alias
= uint32(val
);
2130 // nlassert( CPrimitiveContext::instance().CurrentPrimitive);
2131 //// nlassert(_Container);
2132 // CPrimitiveContext::instance().CurrentPrimitive->reserveAlias(_Alias);
2133 // // set to null, it will be rewrited by onBranchLink callback
2134 //// _Container = NULL;
2138 // error in format !
2139 nlwarning("CPrimAlias::read: Can't find xml property 'VALUE' in element <ALIAS>");
2145 // error in format !
2146 nlwarning("CPrimAlias::read: Can't find xml element <ALIAS>");
2150 return IPrimitive::read (xmlNode
, filename
, version
, config
);
2152 // Write the primitive
2153 void CPrimAlias::write (xmlNodePtr xmlNode
, const std::string
&filename
) const
2156 xmlNodePtr ptNode
= xmlNewChild(xmlNode
, NULL
, (const xmlChar
*)"ALIAS", NULL
);
2157 WriteInt("VALUE", int(_Alias
), ptNode
);
2159 IPrimitive::write (xmlNode
, filename
);
2162 // Create a copy of this primitive
2163 IPrimitive
*CPrimAlias::copy () const
2165 // NB : this will not call the reserveAlias on the container
2166 CPrimAlias
*pa
= new CPrimAlias(*this);
2168 // clear the alias and container reference
2170 // pa->_Container = 0;
2174 // serial for binary save
2175 void CPrimAlias::serial (NLMISC::IStream
&f
)
2177 IPrimitive::serial(f
);
2181 // if (f.isReading())
2183 // nlassert(_Container);
2184 // _Container->reserveAlias(_Alias);
2189 // ***************************************************************************
2191 // ***************************************************************************
2193 CPrimitives::CPrimitives () :
2196 // init the alias generator
2197 _LastGeneratedAlias
= 0;
2198 _AliasStaticPart
= 0;
2200 RootNode
= static_cast<CPrimNode
*> (CClassRegistry::create ("CPrimNode"));
2202 // get the current ligo context (if any)
2203 _LigoConfig
= CPrimitiveContext::instance().CurrentLigoConfig
;
2206 // ***************************************************************************
2208 CPrimitives::CPrimitives (const CPrimitives
&other
)
2211 // _LastGeneratedAlias = other._LastGeneratedAlias;
2212 // // get the current ligo context (if any)
2213 // _LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig;
2215 // CPrimitives *temp = CPrimitiveContext::instance().CurrentPrimitive;
2216 // CPrimitiveContext::instance().CurrentPrimitive = this;
2217 // // copy the nodes
2218 // RootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());
2219 // RootNode->branchLink();
2221 // CPrimitiveContext::instance().CurrentPrimitive = temp;
2224 // ***************************************************************************
2226 CPrimitives::~CPrimitives ()
2231 // ***************************************************************************
2233 uint32
CPrimitives::getAliasStaticPart()
2235 return _AliasStaticPart
;
2238 // ***************************************************************************
2240 void CPrimitives::setAliasStaticPart(uint32 staticPart
)
2242 _AliasStaticPart
= staticPart
;
2245 // ***************************************************************************
2247 uint32
CPrimitives::buildFullAlias(uint32 dynamicPart
)
2251 return _LigoConfig
->buildAlias(_AliasStaticPart
, dynamicPart
, true);
2258 // ***************************************************************************
2260 uint32
CPrimitives::genAlias(IPrimitive
*prim
, uint32 preferedAlias
)
2262 nlassert(_LigoConfig
);
2265 if (preferedAlias
!= 0)
2267 // only dynamic part allowed here
2268 nlassert(preferedAlias
== (preferedAlias
& _LigoConfig
->getDynamicAliasMask()));
2269 // check is the prefered alias is not already in use
2270 map
<uint32
, IPrimitive
*>::iterator
it(_AliasInUse
.find(preferedAlias
));
2271 if (it
== _AliasInUse
.end())
2273 // this alias is available, just use it
2274 // nldebug("Alias: added alias %u, %u alias used", preferedAlias, _AliasInUse.size()+1);
2275 _AliasInUse
.insert(make_pair(preferedAlias
, prim
));
2276 return preferedAlias
;
2280 // check who own the alias now
2281 if (it
->second
== prim
)
2283 // ok, the alias is already own by this primitive
2284 // nldebug("Alias: using alias %u, %u alias used", preferedAlias, _AliasInUse.size()+1);
2285 return preferedAlias
;
2290 // make sure there are some free aliases
2291 uint32 mask
= _LigoConfig
->getDynamicAliasMask();
2292 nlassert(_AliasInUse
.size() < mask
);
2294 // increment alias counter
2295 ++_LastGeneratedAlias
;
2296 // mask with the dynamic alias mask
2297 _LastGeneratedAlias
&= _LigoConfig
->getDynamicAliasMask();
2299 ret
= _LastGeneratedAlias
;
2301 while (_AliasInUse
.find(ret
) != _AliasInUse
.end())
2303 // this alias is already in use ! generate a new one
2304 // increment, mask, affect...
2305 ++_LastGeneratedAlias
;
2306 _LastGeneratedAlias
&= _LigoConfig
->getDynamicAliasMask();
2307 ret
= _LastGeneratedAlias
;
2311 // nldebug("Alias: added alias %u, %u alias in use", ret, _AliasInUse.size()+1);
2312 _AliasInUse
.insert(make_pair(ret
, prim
));
2315 prim
->onModifyPrimitive (*this);
2320 //void CPrimitives::reserveAlias(uint32 dynamicAlias)
2322 // // need ligo config
2323 // nlassert(_LigoConfig);
2324 // // only dynamic part allowed here
2325 // nlassert(dynamicAlias == (dynamicAlias & _LigoConfig->getDynamicAliasMask()));
2326 // std::set<uint32>::iterator it(_AliasInUse.find(dynamicAlias));
2327 // // warn if already found
2328 // if (it != _AliasInUse.end())
2330 // const string &fileName = _LigoConfig->getFileNameForStaticAlias(_AliasStaticPart);
2331 // if (fileName.empty())
2332 // nlwarning("Dynamic Alias %u is already in use");
2334 // nlwarning("Dynamic Alias %u is already in use in file '%s'",
2336 // fileName.c_str());
2340 // // insert the alias
2341 // nldebug("Alias: added alias %u, %u alias in use", dynamicAlias, _AliasInUse.size()+1);
2342 // _AliasInUse.insert(dynamicAlias);
2345 void CPrimitives::releaseAlias(IPrimitive
*prim
, uint32 alias
)
2348 nlassert(_LigoConfig
);
2349 // only dynamic part allowed here
2350 nlassert(alias
== (alias
& _LigoConfig
->getDynamicAliasMask()));
2351 std::map
<uint32
, IPrimitive
*>::iterator
it(_AliasInUse
.find(alias
));
2353 nlassert(it
!= _AliasInUse
.end());
2355 if (it
->second
!= prim
)
2357 nlwarning("CPrimitives::releaseAlias: The alias %u is own by another primitive !", alias
);
2361 // remove this alias
2362 // nldebug("Alias: remove alias %u, %u alias left", it->first, _AliasInUse.size()-1);
2363 _AliasInUse
.erase(it
);
2366 // ***************************************************************************
2368 void CPrimitives::forceAlias(CPrimAlias
*prim
, uint32 alias
)
2371 nlassert(_LigoConfig
);
2372 // only dynamic part allowed here
2373 nlassert(alias
== (alias
& _LigoConfig
->getDynamicAliasMask()));
2375 // store the alias in the primitive
2376 prim
->_Alias
= alias
;
2378 std::map
<uint32
, IPrimitive
*>::iterator
it(_AliasInUse
.find(alias
));
2379 if (it
!= _AliasInUse
.end() && it
->second
!= prim
)
2381 // we need to alloc and set a new alias for the current alias holder
2382 CPrimAlias
*pa
= static_cast<CPrimAlias
*>(const_cast<IPrimitive
*>(it
->second
));
2384 // reserve the alias for the new primitive
2388 // and regen an alias for the old
2393 // just store the association
2394 _AliasInUse
.insert(make_pair(alias
, prim
));
2399 // ***************************************************************************
2401 uint32
CPrimitives::getLastGeneratedAlias()
2403 return _LastGeneratedAlias
;
2406 // ***************************************************************************
2408 IPrimitive
*CPrimitives::getPrimitiveByAlias(uint32 primAlias
)
2410 // check the static part of the alias
2411 uint32 staticAlias
= _LigoConfig
->getStaticAliasMask() & primAlias
;
2412 staticAlias
= staticAlias
>> _LigoConfig
->getDynamicAliasSize();
2413 if (staticAlias
!= _AliasStaticPart
)
2416 // clear the static part before searching
2417 primAlias
&= _LigoConfig
->getDynamicAliasMask();
2419 std::map
<uint32
, IPrimitive
*>::const_iterator
it(_AliasInUse
.find(primAlias
));
2421 if (it
!= _AliasInUse
.end())
2422 return it
->second
->getParent();
2427 // ***************************************************************************
2429 void CPrimitives::buildPrimitiveWithAliasList(std::map
<uint32
, IPrimitive
*> &result
)
2431 nlassert(_LigoConfig
!= NULL
);
2433 std::map
<uint32
, IPrimitive
*>::iterator
first(_AliasInUse
.begin()), last(_AliasInUse
.end());
2434 for (; first
!= last
; ++first
)
2436 result
.insert(make_pair(_LigoConfig
->buildAlias(_AliasStaticPart
, first
->first
), first
->second
->getParent()));
2440 // ***************************************************************************
2442 CPrimitives
& CPrimitives::operator= (const CPrimitives
&other
)
2444 // RootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());
2447 _AliasStaticPart
= other
._AliasStaticPart
;
2448 _LastGeneratedAlias
= other
._LastGeneratedAlias
;
2449 // get the current ligo context (if any)
2450 _LigoConfig
= CPrimitiveContext::instance().CurrentLigoConfig
;
2452 CPrimitives
*temp
= CPrimitiveContext::instance().CurrentPrimitive
;
2453 CPrimitiveContext::instance().CurrentPrimitive
= this;
2455 RootNode
= static_cast<CPrimNode
*> (((IPrimitive
*)other
.RootNode
)->copy ());
2456 RootNode
->branchLink();
2458 CPrimitiveContext::instance().CurrentPrimitive
= temp
;
2463 // ***************************************************************************
2465 bool CPrimitives::read (xmlNodePtr xmlNode
, const std::string
&filename
, CLigoConfig
&config
)
2469 _Filename
= CFile::getFilename(filename
);
2472 // try to get the static alias mapping
2473 _AliasStaticPart
= _LigoConfig
->getFileStaticAliasMapping(CFile::getFilename(filename
));
2476 // Clear the primitives
2477 RootNode
->removeChildren ();
2478 RootNode
->removeProperties ();
2481 if (strcmp ((const char*)xmlNode
->name
, "PRIMITIVES") == 0)
2484 string versionName
= "0";
2485 if (GetPropertyString (versionName
, filename
, xmlNode
, "VERSION"))
2488 uint32 version
= atoi (versionName
.c_str ());
2490 // Check the version
2491 if (version
<= NLLIGO_PRIMITIVE_VERSION
)
2493 // Read the primitives
2494 xmlNode
= GetFirstChildNode (xmlNode
, filename
, "ROOT_PRIMITIVE");
2499 xmlNodePtr subNode
= GetFirstChildNode(xmlNode
, filename
, "ALIAS");
2503 ReadUInt("LAST_GENERATED", temp
, filename
, subNode
);
2504 _LastGeneratedAlias
= temp
;
2507 _LastGeneratedAlias
= 0;
2510 _LastGeneratedAlias
= 0;
2512 // Read the primitive tree
2513 ((IPrimitive
*)RootNode
)->read (xmlNode
, filename
, version
, config
);
2518 Error (filename
, "CPrimitives::read : Unknown file version (%u)", version
);
2529 XMLError (xmlNode
, filename
, "This XML document is not a NeL primitive file");
2536 // ***************************************************************************
2538 void CPrimitives::write (xmlDocPtr doc
, const std::string
&filename
) const
2543 xmlNodePtr primNode
= xmlNewDocNode (doc
, NULL
, (const xmlChar
*)"PRIMITIVES", NULL
);
2544 xmlDocSetRootElement (doc
, primNode
);
2546 write (primNode
, filename
);
2549 // ***************************************************************************
2551 void CPrimitives::write (xmlNodePtr root
, const std::string
&filename
) const
2556 xmlSetProp (root
, (const xmlChar
*)"VERSION", (const xmlChar
*)toString (NLLIGO_PRIMITIVE_VERSION
).c_str ());
2558 // The primitive root node
2559 xmlNodePtr nameNode
= xmlNewChild ( root
, NULL
, (const xmlChar
*)"ROOT_PRIMITIVE", NULL
);
2560 xmlNodePtr subNode
= xmlNewChild ( nameNode
, NULL
, (const xmlChar
*)"ALIAS", NULL
);
2561 WriteUInt("LAST_GENERATED", _LastGeneratedAlias
, subNode
);
2563 // Write the primitive tree
2564 ((IPrimitive
*)RootNode
)->write (nameNode
, filename
);
2567 // ***************************************************************************
2569 void CPrimitives::serial(NLMISC::IStream
&f
)
2571 uint currentVersion
= NLLIGO_PRIMITIVE_VERSION
;
2572 f
.serialVersion(currentVersion
);
2574 if (currentVersion
== 0)
2576 f
.serial(_LastGeneratedAlias
);
2581 RootNode
->removeChildren ();
2582 RootNode
->removeProperties ();
2584 f
.serialPolyPtr(RootNode
);
2585 f
.serial(_Filename
);
2586 if (f
.isReading() && _LigoConfig
)
2588 _AliasStaticPart
= _LigoConfig
->getFileStaticAliasMapping(_Filename
);
2592 // ***************************************************************************
2594 void CPrimitives::convertAddPrimitive (IPrimitive
*child
, const IPrimitive
*prim
, bool hidden
)
2597 IPrimitive
*primitive
= NULL
;
2599 // What kind of primitive ?
2600 const CPrimPoint
*oldPoint
= dynamic_cast<const CPrimPoint
*>(prim
);
2603 // Create a primitive
2604 CPrimPoint
*point
= static_cast<CPrimPoint
*> (CClassRegistry::create ("CPrimPoint"));
2613 const CPrimPath
*oldPath
= dynamic_cast<const CPrimPath
*>(prim
);
2616 // Create a primitive
2617 CPrimPath
*path
= static_cast<CPrimPath
*> (CClassRegistry::create ("CPrimPath"));
2625 const CPrimZone
*oldZone
= safe_cast
<const CPrimZone
*>(prim
);
2628 // Create a primitive
2629 CPrimZone
*zone
= static_cast<CPrimZone
*> (CClassRegistry::create ("CPrimZone"));
2638 // Primitive has been created ?
2641 // Create a property for the name
2642 CPropertyString
*nameProp
= new CPropertyString
;
2643 // nameProp->String = prim->Name;
2646 primitive
->addPropertyByName ("name", nameProp
);
2648 // The primitive is hidden ?
2651 // Create a property for hidden
2652 nameProp
= new CPropertyString
;
2655 primitive
->addPropertyByName ("hidden", nameProp
);
2659 child
->insertChild (primitive
);
2663 // ***************************************************************************
2665 void CPrimitives::convertPrimitive (const IPrimitive
*prim
, bool hidden
)
2667 // Look for the group
2668 uint numChildren
= RootNode
->getNumChildren ();
2670 for (j
=0; j
<numChildren
; j
++)
2673 nlverify (RootNode
->getChild (child
, j
));
2674 const IProperty
*prop
;
2675 if (child
->getPropertyByName ("name", prop
))
2678 const CPropertyString
*name
= dynamic_cast<const CPropertyString
*>(prop
);
2682 /* if (name->String == prim->Layer)
2684 convertAddPrimitive (child, prim, hidden);
2695 CPrimNode
*primNode
= static_cast<CPrimNode
*> (CClassRegistry::create ("CPrimNode"));
2697 // Create a property for the layer
2698 CPropertyString
*nameProp
= new CPropertyString
;
2699 // nameProp->String = prim->Layer;
2702 primNode
->addPropertyByName ("name", nameProp
);
2705 RootNode
->insertChild (primNode
);
2707 // Add the primitive
2708 convertAddPrimitive (primNode
, prim
, hidden
);
2712 // ***************************************************************************
2714 void CPrimitives::convert (const CPrimRegion
®ion
)
2717 RootNode
->removeChildren ();
2718 RootNode
->removeProperties ();
2720 // For each primitives
2722 for (i
=0; i
<region
.VPoints
.size (); i
++)
2724 convertPrimitive (&(region
.VPoints
[i
]), region
.VHidePoints
[i
]);
2726 for (i
=0; i
<region
.VPaths
.size (); i
++)
2728 convertPrimitive (&(region
.VPaths
[i
]), region
.VHidePaths
[i
]);
2730 for (i
=0; i
<region
.VZones
.size (); i
++)
2732 convertPrimitive (&(region
.VZones
[i
]), region
.VHideZones
[i
]);
2736 // ***************************************************************************
2738 CPrimitiveContext::CPrimitiveContext():
2739 CurrentLigoConfig(NULL
),
2740 CurrentPrimitive(NULL
)
2745 static bool LIGORegistered
= false;
2750 if( LIGORegistered
)
2752 nlinfo( "LIGO classes have already been registered." );
2756 NLMISC_REGISTER_CLASS(CPropertyString
);
2757 NLMISC_REGISTER_CLASS(CPropertyStringArray
);
2758 NLMISC_REGISTER_CLASS(CPropertyColor
);
2759 NLMISC_REGISTER_CLASS(CPrimNode
);
2760 NLMISC_REGISTER_CLASS(CPrimPoint
);
2761 NLMISC_REGISTER_CLASS(CPrimPath
);
2762 NLMISC_REGISTER_CLASS(CPrimZone
);
2763 NLMISC_REGISTER_CLASS(CPrimAlias
);
2765 LIGORegistered
= true;
2768 // ***************************************************************************
2770 } // namespace NLLIGO