primitive.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "nel/misc/types_nl.h"
00025 #include "nel/misc/hierarchical_timer.h"
00026 #include "nel/ligo/primitive.h"
00027 #include "nel/ligo/ligo_config.h"
00028 #include "nel/ligo/primitive_class.h"
00029 #include "nel/misc/i_xml.h"
00030 #include "nel/misc/path.h"
00031 
00032 using namespace NLMISC;
00033 using namespace std;
00034 
00035 const uint32 NLLIGO_PRIMITIVE_VERSION = 1;
00036 
00037 namespace NLLIGO
00038 {
00039 
00040 CPrimitiveContext   *CPrimitiveContext::_Instance = NULL;
00041 
00042 
00043 // ***************************************************************************
00044 // XML helpers
00045 // ***************************************************************************
00046 
00047 void Error (const char *filename, const char *format, ...)
00048 {
00049     va_list args;
00050     va_start( args, format );
00051     char buffer[1024];
00052     vsnprintf( buffer, 1024, format, args );
00053     va_end( args );
00054 
00055     nlwarning ("In File (%s) %s", filename, buffer);
00056 }
00057 
00058 // ***************************************************************************
00059 
00060 void XMLError (xmlNodePtr xmlNode, const char *filename, const char *format, ... )
00061 {
00062     va_list args;
00063     va_start( args, format );
00064     char buffer[1024];
00065     vsnprintf( buffer, 1024, format, args );
00066     va_end( args );
00067 
00068     Error (filename, "node (%s), line (%d) : %s", xmlNode->name, (ptrdiff_t)xmlNode->content, buffer);
00069 }
00070 
00071 
00072 // ***************************************************************************
00073 
00074 xmlNodePtr GetFirstChildNode (xmlNodePtr xmlNode, const char *filename, const char *childName)
00075 {
00076     // Call the CIXml version
00077     xmlNodePtr result = CIXml::getFirstChildNode (xmlNode, childName);
00078     if (result) return result;
00079 
00080     // Output a formated error
00081     XMLError (xmlNode, filename, "Can't find XML node named (%s)", childName);
00082     return NULL;
00083 }
00084 
00085 // ***************************************************************************
00086 
00087 bool GetPropertyString (string &result, const char *filename, xmlNodePtr xmlNode, const char *propName)
00088 {
00089     // Call the CIXml version
00090     if (!CIXml::getPropertyString (result, xmlNode, propName))
00091     {
00092         // Output a formated error
00093         XMLError (xmlNode, filename, "Can't find XML node property (%s)", propName);
00094         return false;
00095     }
00096     return true;
00097 }
00098 
00099 // ***************************************************************************
00100 
00101 bool ReadInt (const char *propName, int &result, const char *filename, xmlNodePtr xmlNode)
00102 {
00103     string value;
00104     if (GetPropertyString (value, filename, xmlNode, propName))
00105     {
00106         result = atoi (value.c_str ());
00107         return true;
00108     }
00109     return false;
00110 }
00111 
00112 // ***************************************************************************
00113 
00114 void WriteInt (const char *propName, int value, xmlNodePtr xmlNode)
00115 {
00116     // Set properties
00117     xmlSetProp (xmlNode, (const xmlChar*)propName, (const xmlChar*)(toString (value).c_str ()));
00118 }
00119 
00120 // ***************************************************************************
00121 
00122 bool ReadUInt (const char *propName, uint &result, const char *filename, xmlNodePtr xmlNode)
00123 {
00124     string value;
00125     if (GetPropertyString (value, filename, xmlNode, propName))
00126     {
00127         result = strtoul (value.c_str (), NULL, 10);
00128         return true;
00129     }
00130     return false;
00131 }
00132 
00133 // ***************************************************************************
00134 
00135 void WriteUInt (const char *propName, uint value, xmlNodePtr xmlNode)
00136 {
00137     // Set properties
00138     xmlSetProp (xmlNode, (const xmlChar*)propName, (const xmlChar*)(toString (value).c_str ()));
00139 }
00140 
00141 // ***************************************************************************
00142 
00143 bool ReadFloat (const char *propName, float &result, const char *filename, xmlNodePtr xmlNode)
00144 {
00145     string value;
00146     if (GetPropertyString (value, filename, xmlNode, propName))
00147     {
00148         result = (float)atof (value.c_str ());
00149         return true;
00150     }
00151     return false;
00152 }
00153 
00154 // ***************************************************************************
00155 
00156 void WriteFloat (const char *propName, float value, xmlNodePtr xmlNode)
00157 {
00158     // Set properties
00159     xmlSetProp (xmlNode, (const xmlChar*)propName, (const xmlChar*)(toString (value).c_str ()));
00160 }
00161 
00162 // ***************************************************************************
00163 
00164 bool ReadVector (CPrimVector &point, const char *filename, xmlNodePtr xmlNode)
00165 {
00166     CPrimVector pos;
00167     if (ReadFloat ("X", pos.x, filename, xmlNode))
00168     {
00169         if (ReadFloat ("Y", pos.y, filename, xmlNode))
00170         {
00171             if (ReadFloat ("Z", pos.z, filename, xmlNode))
00172             {
00173                 pos.Selected = false;
00174                 string result;
00175                 if (CIXml::getPropertyString (result, xmlNode, "SELECTED"))
00176                 {
00177                     if (result == "true")
00178                         pos.Selected = true;
00179                 }
00180                 point = pos;
00181                 return true;
00182             }
00183         }
00184     }
00185     return false;
00186 }
00187 
00188 // ***************************************************************************
00189 
00190 void WriteVector (const CPrimVector &point, xmlNodePtr xmlNode)
00191 {
00192     // Set properties
00193     xmlSetProp (xmlNode, (const xmlChar*)"X", (const xmlChar*)(toString (point.x).c_str ()));
00194     xmlSetProp (xmlNode, (const xmlChar*)"Y", (const xmlChar*)(toString (point.y).c_str ()));
00195     xmlSetProp (xmlNode, (const xmlChar*)"Z", (const xmlChar*)(toString (point.z).c_str ()));
00196     if (point.Selected)
00197         xmlSetProp (xmlNode, (const xmlChar*)"SELECTED", (const xmlChar*)"true");
00198 }
00199 
00200 
00201 // ***************************************************************************
00202 
00203 bool GetNodeString (string &result, const char *filename, xmlNodePtr xmlNode, const char *nodeName)
00204 {
00205     // Look for the node
00206     xmlNodePtr node = CIXml::getFirstChildNode (xmlNode, nodeName);
00207     if (!node)
00208     {
00209         XMLError (xmlNode, filename, "Can't find XML node named (%s)", nodeName);
00210         return false;
00211     }
00212 
00213     // Get the node string
00214     if (!CIXml::getContentString (result, node))
00215     {
00216         XMLError (xmlNode, filename, "Can't find any text in the node named (%s)", nodeName);
00217         return false;
00218     }
00219 
00220     return true;
00221 }
00222 
00223 // ***************************************************************************
00224 
00225 bool GetContentString (string &result, const char *filename, xmlNodePtr xmlNode)
00226 {
00227     // Get the node string
00228     if (!CIXml::getContentString (result, xmlNode))
00229     {
00230         XMLError (xmlNode, filename, "Can't find any text in the node");
00231         return false;
00232     }
00233 
00234     return true;
00235 }
00236 
00237 // ***************************************************************************
00238 // CPropertyString
00239 // ***************************************************************************
00240 
00241 CPropertyString::CPropertyString (const char *str)
00242 {
00243     String = str;
00244 }
00245 
00246 CPropertyString::CPropertyString (const std::string &str)
00247 {
00248     String = str;
00249 }
00250 
00251 // ***************************************************************************
00252 
00253 CPropertyString::CPropertyString (const char *str, bool _default)
00254 {
00255     String = str;
00256     Default = _default;
00257 }
00258 
00259 // ***************************************************************************
00260 // CPropertyStringArray
00261 // ***************************************************************************
00262 
00263 CPropertyStringArray::CPropertyStringArray (const std::vector<std::string> &stringArray)
00264 {
00265     StringArray = stringArray;
00266 }
00267 
00268 // ***************************************************************************
00269 
00270 CPropertyStringArray::CPropertyStringArray (const std::vector<std::string> &stringArray, bool _default)
00271 {
00272     StringArray = stringArray;
00273     Default = _default;
00274 }
00275 
00276 // ***************************************************************************
00277 
00278 void CPrimPoint::serial (NLMISC::IStream &f)
00279 {
00280     // serial base info
00281     IPrimitive::serial(f);
00282     f.serial(Point);
00283     f.serial(Angle);
00284 }
00285 
00286 // ***************************************************************************
00287 void CPrimPath::serial (NLMISC::IStream &f)
00288 {
00289     IPrimitive::serial(f);
00290     f.serialCont(VPoints);
00291 }
00292 
00293 // ***************************************************************************
00294 
00295 bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<CPrimVector> &points)
00296 {
00297     uint32 i;
00298     CVector vMin, vMax;
00299 
00300     // Point or line can't contains !
00301     if (points.size() < 3)
00302         return false;
00303 
00304     // Get the bounding rectangle of the zone
00305     vMax = vMin = points[0];
00306     for (i = 0; i < points.size(); ++i)
00307     {
00308         if (vMin.x > points[i].x)
00309             vMin.x = points[i].x;
00310         if (vMin.y > points[i].y)
00311             vMin.y = points[i].y;
00312 
00313         if (vMax.x < points[i].x)
00314             vMax.x = points[i].x;
00315         if (vMax.y < points[i].y)
00316             vMax.y = points[i].y;
00317     }
00318 
00319     if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))
00320         return false;
00321 
00322     uint32 nNbIntersection = 0;
00323     for (i = 0; i < points.size(); ++i)
00324     {
00325         const CVector &p1 = points[i];
00326         const CVector &p2 = points[(i+1)%points.size()];
00327 
00328         if (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))
00329             continue;
00330         if (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))
00331             continue;
00332         float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));
00333         if (xinter > v.x)
00334             ++nNbIntersection;
00335     }
00336     if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside
00337         return true;
00338     else
00339         return false;
00340 }
00341 
00342 // ***************************************************************************
00343 
00344 bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<NLMISC::CVector> &points)
00345 {
00346     uint32 i;
00347     CVector vMin, vMax;
00348 
00349     // Point or line can't contains !
00350     if (points.size() < 3)
00351         return false;
00352 
00353     // Get the bounding rectangle of the zone
00354     vMax = vMin = points[0];
00355     for (i = 0; i < points.size(); ++i)
00356     {
00357         if (vMin.x > points[i].x)
00358             vMin.x = points[i].x;
00359         if (vMin.y > points[i].y)
00360             vMin.y = points[i].y;
00361 
00362         if (vMax.x < points[i].x)
00363             vMax.x = points[i].x;
00364         if (vMax.y < points[i].y)
00365             vMax.y = points[i].y;
00366     }
00367 
00368     if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))
00369         return false;
00370 
00371     uint32 nNbIntersection = 0;
00372     for (i = 0; i < points.size(); ++i)
00373     {
00374         const CVector &p1 = points[i];
00375         const CVector &p2 = points[(i+1)%points.size()];
00376 
00377         if (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))
00378             continue;
00379         if (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))
00380             continue;
00381         float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));
00382         if (xinter > v.x)
00383             ++nNbIntersection;
00384     }
00385     if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside
00386         return true;
00387     else
00388         return false;
00389 }
00390 
00391 // ***************************************************************************
00392 // CPrimNode
00393 // ***************************************************************************
00394 
00395 bool CPrimNode::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)
00396 {
00397     return IPrimitive::read (xmlNode, filename, version, config);
00398 }
00399 
00400 // ***************************************************************************
00401 
00402 uint CPrimNode::getNumVector () const
00403 {
00404     return 0;
00405 }
00406 
00407 // ***************************************************************************
00408 
00409 const CPrimVector *CPrimNode::getPrimVector () const
00410 {
00411     return NULL;
00412 }
00413 
00414 // ***************************************************************************
00415 
00416 CPrimVector *CPrimNode::getPrimVector ()
00417 {
00418     return NULL;
00419 }
00420 
00421 // ***************************************************************************
00422 
00423 NLLIGO::IPrimitive *CPrimNode::copy () const
00424 {
00425     return new CPrimNode (*this);
00426 }
00427 
00428 
00429 // ***************************************************************************
00430 // CPrimNode
00431 // ***************************************************************************
00432 
00433 /*void CPrimNode::operator= (const CPrimNode &node)
00434 {
00435     // Copy the IPrimitive
00436     IPrimitive::operator= (node);
00437 }
00438 
00439 // ***************************************************************************
00440 
00441 void CPrimPoint::operator= (const CPrimPoint &node)
00442 {
00443     // Copy the IPrimitive
00444     IPrimitive::operator= (node);
00445 }
00446 
00447 // ***************************************************************************
00448 
00449 void CPrimPath::operator= (const CPrimPath &node)
00450 {
00451     // Copy the IPrimitive
00452 }
00453 
00454 // ***************************************************************************
00455 
00456 void CPrimZone::operator= (const CPrimZone &node)
00457 {
00458     // Copy the IPrimitive
00459     IPrimitive::operator= (node);
00460 }
00461 */
00462 
00463 // ***************************************************************************
00464 
00465 uint CPrimPoint::getNumVector () const
00466 {
00467     return 1;
00468 }
00469 
00470 // ***************************************************************************
00471 
00472 const CPrimVector *CPrimPoint::getPrimVector () const
00473 {
00474     return &Point;
00475 }
00476 
00477 // ***************************************************************************
00478 
00479 CPrimVector *CPrimPoint::getPrimVector ()
00480 {
00481     return &Point;
00482 }
00483 
00484 // ***************************************************************************
00485 
00486 NLLIGO::IPrimitive *CPrimPoint::copy () const
00487 {
00488     return new CPrimPoint (*this);
00489 }
00490 
00491 // ***************************************************************************
00492 
00493 bool CPrimPoint::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)
00494 {
00495     // Read points
00496     xmlNodePtr ptNode = GetFirstChildNode (xmlNode, filename, "PT");
00497     if (ptNode)
00498     {
00499         // Read a vector
00500         if (!ReadVector (Point, filename, ptNode))
00501             return false;
00502 
00503         ptNode = CIXml::getFirstChildNode (xmlNode, "ANGLE");
00504         if (ptNode)
00505         {
00506             // Read a float
00507             if (!ReadFloat ("VALUE", Angle, filename, ptNode))
00508                 return false;
00509         }
00510         else
00511             Angle = 0;
00512     }
00513     else
00514     {
00515         return false;
00516     }
00517 
00518     return IPrimitive::read (xmlNode, filename, version, config);
00519 }
00520 
00521 // ***************************************************************************
00522 
00523 void CPrimPoint::write (xmlNodePtr xmlNode, const char *filename) const
00524 {
00525     // Save the point
00526     xmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"PT", NULL);
00527     WriteVector (Point, ptNode);
00528 
00529     // Save the angle
00530     if (Angle != 0)
00531     {
00532         xmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"ANGLE", NULL);
00533         WriteFloat ("VALUE", Angle, ptNode);
00534     }
00535 
00536     IPrimitive::write (xmlNode, filename);
00537 }
00538 
00539 // ***************************************************************************
00540 // CPrimPath
00541 // ***************************************************************************
00542 
00543 uint CPrimPath::getNumVector () const
00544 {
00545     return VPoints.size ();
00546 }
00547 
00548 // ***************************************************************************
00549 
00550 const CPrimVector *CPrimPath::getPrimVector () const
00551 {
00552     if (VPoints.empty())
00553         return NULL;
00554     return &(VPoints[0]);
00555 }
00556 
00557 // ***************************************************************************
00558 
00559 NLLIGO::IPrimitive *CPrimPath::copy () const
00560 {
00561     return new CPrimPath (*this);
00562 }
00563 
00564 // ***************************************************************************
00565 
00566 CPrimVector *CPrimPath::getPrimVector ()
00567 {
00568     if (VPoints.empty())
00569         return NULL;
00570     return &(VPoints[0]);
00571 }
00572 
00573 // ***************************************************************************
00574 
00575 bool CPrimPath::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)
00576 {
00577     // Read points
00578     VPoints.clear ();
00579     VPoints.reserve (CIXml::countChildren (xmlNode, "PT"));
00580     xmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, "PT");
00581     if (ptNode)
00582     {
00583         do
00584         {
00585             // Read a vector
00586             VPoints.push_back (CPrimVector ());
00587             if (!ReadVector (VPoints.back (), filename, ptNode))
00588                 return false;
00589 
00590             ptNode = CIXml::getNextChildNode (ptNode, "PT");
00591         }
00592         while (ptNode);
00593     }
00594 
00595     return IPrimitive::read (xmlNode, filename, version, config);
00596 }
00597 
00598 // ***************************************************************************
00599 
00600 void CPrimPath::write (xmlNodePtr xmlNode, const char *filename) const
00601 {
00602     // Save the points
00603     for (uint i=0; i<VPoints.size (); i++)
00604     {
00605         xmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"PT", NULL);
00606         WriteVector (VPoints[i], ptNode);
00607     }
00608 
00609     IPrimitive::write (xmlNode, filename);
00610 }
00611 
00612 // ***************************************************************************
00613 // CPrimZone
00614 // ***************************************************************************
00615 
00616 uint CPrimZone::getNumVector () const
00617 {
00618     return VPoints.size ();
00619 }
00620 
00621 // ***************************************************************************
00622 
00623 const CPrimVector *CPrimZone::getPrimVector () const
00624 {
00625     if (VPoints.empty())
00626         return NULL;
00627     return &(VPoints[0]);
00628 }
00629 
00630 // ***************************************************************************
00631 
00632 NLLIGO::IPrimitive *CPrimZone::copy () const
00633 {
00634     return new CPrimZone (*this);
00635 }
00636 
00637 // ***************************************************************************
00638 
00639 CPrimVector *CPrimZone::getPrimVector ()
00640 {
00641     if(VPoints.empty()) return 0;
00642     return &(VPoints[0]);
00643 }
00644 
00645 // ***************************************************************************
00646 
00647 bool CPrimZone::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)
00648 {
00649     // Read points
00650     VPoints.clear ();
00651     VPoints.reserve (CIXml::countChildren (xmlNode, "PT"));
00652     xmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, "PT");
00653     if (ptNode)
00654     {
00655         do
00656         {
00657             // Read a vector
00658             VPoints.push_back (CPrimVector ());
00659             if (!ReadVector (VPoints.back (), filename, ptNode))
00660                 return false;
00661 
00662             ptNode = CIXml::getNextChildNode (ptNode, "PT");
00663         }
00664         while (ptNode);
00665     }
00666 
00667     return IPrimitive::read (xmlNode, filename, version, config);
00668 }
00669 
00670 // ***************************************************************************
00671 
00672 void CPrimZone::write (xmlNodePtr xmlNode, const char *filename) const
00673 {
00674     // Save the points
00675     for (uint i=0; i<VPoints.size (); i++)
00676     {
00677         xmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"PT", NULL);
00678         WriteVector (VPoints[i], ptNode);
00679     }
00680 
00681     IPrimitive::write (xmlNode, filename);
00682 }
00683 
00684 // ***************************************************************************
00685 
00686 bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<CPrimVector> &points, float &distance, NLMISC::CVector &nearPos, bool isPath)
00687 {
00688     H_AUTO(NLLIGO_Contains1)
00689     uint32 i;
00690     CVector vMin, vMax;
00691     float nearest = FLT_MAX;
00692     CVector pos;
00693 
00694     // Point or line can't contains !
00695     if (points.size() < 3 || isPath)
00696     {
00697         // only compute the distance.
00698         if (points.size() == 1)
00699         {
00700             distance = (points[0] - v).norm();
00701             nearPos = points[0];
00702         }
00703         else if (points.size() == 2)
00704         {
00705             distance = getSegmentDist(v, points[0], points[1], nearPos);
00706         }
00707         else
00708         {
00709             // compute nearest segment
00710             for (i = 0; i < points.size()-1; ++i)
00711             {
00712                 const CVector &p1 = points[i];
00713                 const CVector &p2 = points[i+1];
00714 
00715                 float dist = getSegmentDist(v, p1, p2, pos);
00716                 if( dist < nearest)
00717                 {
00718                     nearest = dist;
00719                     nearPos = pos;
00720                 }
00721             }
00722             distance = nearest;
00723         }
00724         return false;
00725     }
00726 
00727     // Get the bounding rectangle of the zone
00728     vMax = vMin = points[0];
00729     for (i = 0; i < points.size(); ++i)
00730     {
00731         vMin.x = min(vMin.x, points[i].x);
00732         vMin.y = min(vMin.y, points[i].y);
00733         vMax.x = max(vMax.x, points[i].x);
00734         vMax.y = max(vMax.y, points[i].y);
00735     }
00736 
00737     if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))
00738     {
00739         // find the nearest distance of all segment
00740         for (uint i=0; i<points.size(); ++i)
00741         {
00742             float dist = getSegmentDist(v, points[i], points[(i+1) % points.size()], pos);
00743 
00744             if (dist < nearest)
00745             {
00746                 nearest = dist;
00747                 nearPos = pos;
00748             }
00749         }
00750         distance = nearest;
00751         return false;
00752     }
00753 
00754     uint32 nNbIntersection = 0;
00755     for (i = 0; i < points.size(); ++i)
00756     {
00757         const CVector &p1 = points[i];
00758         const CVector &p2 = points[(i+1)%points.size()];
00759 
00760         float dist = getSegmentDist(v, p1, p2, pos);
00761         if( dist < nearest)
00762         {
00763             nearest = dist;
00764             nearPos = pos;
00765         }
00766 
00767         if (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))
00768             continue;
00769         if (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))
00770             continue;
00771         float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));
00772         if (xinter > v.x)
00773             ++nNbIntersection;
00774     }
00775 
00776     distance = nearest;
00777     if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside
00778         return true;
00779     else
00780         return false;
00781 }
00782 
00783 // ***************************************************************************
00784 
00785 bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<CVector> &points, float &distance, NLMISC::CVector &nearPos, bool isPath)
00786 {
00787     H_AUTO(NLLIGO_Contains2)
00788     uint32 i;
00789     CVector vMin, vMax;
00790     float nearest = FLT_MAX;
00791     CVector pos;
00792 
00793     // Point or line can't contains !
00794     if (points.size() < 3 || isPath)
00795     {
00796         // only compute the distance.
00797         if (points.size() == 1)
00798         {
00799             distance = (points[0] - v).norm();
00800             nearPos = points[0];
00801         }
00802         else if (points.size() == 2)
00803         {
00804             distance = getSegmentDist(v, points[0], points[1], nearPos);
00805         }
00806         else
00807         {
00808             // compute nearest segment
00809             for (i = 0; i < points.size()-1; ++i)
00810             {
00811                 const CVector &p1 = points[i];
00812                 const CVector &p2 = points[i+1];
00813 
00814                 float dist = getSegmentDist(v, p1, p2, pos);
00815                 if( dist < nearest)
00816                 {
00817                     nearest = dist;
00818                     nearPos = pos;
00819                 }
00820             }
00821             distance = nearest;
00822         }
00823         return false;
00824     }
00825 
00826     // Get the bounding rectangle of the zone
00827     vMax = vMin = points[0];
00828     for (i = 0; i < points.size(); ++i)
00829     {
00830         vMin.x = min(vMin.x, points[i].x);
00831         vMin.y = min(vMin.y, points[i].y);
00832         vMax.x = max(vMax.x, points[i].x);
00833         vMax.y = max(vMax.y, points[i].y);
00834     }
00835 
00836     if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))
00837     {
00838         // find the nearest distance of all segment
00839         for (uint i=0; i<points.size(); ++i)
00840         {
00841             float dist = getSegmentDist(v, points[i], points[(i+1) % points.size()], pos);
00842 
00843             if (dist < nearest)
00844             {
00845                 nearest = dist;
00846                 nearPos = pos;
00847             }
00848         }
00849         distance = nearest;
00850         return false;
00851     }
00852 
00853     uint32 nNbIntersection = 0;
00854     for (i = 0; i < points.size(); ++i)
00855     {
00856         const CVector &p1 = points[i];
00857         const CVector &p2 = points[(i+1)%points.size()];
00858 
00859         float dist = getSegmentDist(v, p1, p2, pos);
00860         if( dist < nearest)
00861         {
00862             nearest = dist;
00863             nearPos = pos;
00864         }
00865 
00866         if (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))
00867             continue;
00868         if (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))
00869             continue;
00870         float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));
00871         if (xinter > v.x)
00872             ++nNbIntersection;
00873     }
00874 
00875     distance = nearest;
00876     if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside
00877         return true;
00878     else
00879         return false;
00880 }
00881 
00882 // ***************************************************************************
00883 
00884 float CPrimZone::getSegmentDist(const NLMISC::CVector v, const NLMISC::CVector &p1, const NLMISC::CVector &p2, NLMISC::CVector &nearPos)
00885 {
00886     // two points, compute distance to the segment.
00887     CVector V = (p2-p1).normed();
00888     double  length= (p2-p1).norm();
00889     float distance;
00890 
00891     // case where p1==p2
00892     if(length==0.0)
00893     {
00894         nearPos= p1;
00895         distance = (p1-v).norm();
00896     }
00897     // standard case
00898     else
00899     {
00900         float t = (float)((double)((v-p1)*V)/length);
00901         if (t < 0.0f)
00902         {
00903             nearPos = p1;
00904             distance = (p1-v).norm();
00905         }
00906         else if (t > 1.0f)
00907         {
00908             nearPos = p2;
00909             distance = (p2-v).norm();
00910         }
00911         else
00912         {
00913             nearPos = p1 + t*(p2-p1);
00914             distance = (v-nearPos).norm();
00915         }
00916     }
00917 
00918     return distance;
00919 }
00920 
00921 
00922 // ***************************************************************************
00923 NLMISC::CVector CPrimZone::getBarycentre() const
00924 {
00925     CVector sum( CVector::Null );
00926     uint n = VPoints.size();
00927     if ( n != 0 )
00928     {
00929         for ( uint i=0; i!=n; ++i )
00930             sum += VPoints[i];
00931         return sum / (float)n;
00932     }
00933     else
00934         return sum;
00935 }
00936 
00937 // ***************************************************************************
00938 void CPrimZone::getAABox( NLMISC::CVector& cornerMin, NLMISC::CVector& cornerMax ) const
00939 {
00940     cornerMin.x = FLT_MAX;
00941     cornerMin.y = FLT_MAX;
00942     cornerMin.z = 0;
00943     cornerMax.x = -FLT_MAX;
00944     cornerMax.y = -FLT_MAX;
00945     cornerMax.z = 0;
00946     for ( uint i=0; i!=VPoints.size(); ++i )
00947     {
00948         const CVector& p = VPoints[i];
00949         if ( p.x < cornerMin.x )
00950             cornerMin.x = p.x;
00951         if ( p.x > cornerMax.x )
00952             cornerMax.x = p.x;
00953         if ( p.y < cornerMin.y )
00954             cornerMin.y = p.y;
00955         if ( p.y > cornerMax.y )
00956             cornerMax.y = p.y;
00957     }
00958 }
00959 
00960 
00961 // ***************************************************************************
00962 float CPrimZone::getAreaOfAABox() const
00963 {
00964     CVector cornerMin, cornerMax;
00965     getAABox( cornerMin, cornerMax );
00966     return (cornerMax.x-cornerMin.x) * (cornerMax.y-cornerMin.y);
00967 }
00968 
00969 
00970 // ***************************************************************************
00971 void CPrimZone::serial (NLMISC::IStream &f)
00972 {
00973     IPrimitive::serial(f);
00974     f.serialCont(VPoints);
00975 }
00976 
00977 // ***************************************************************************
00978 void CPrimRegion::serial (NLMISC::IStream &f)
00979 {
00980     f.xmlPushBegin ("REGION");
00981 
00982     f.xmlSetAttrib ("NAME");
00983     f.serial (Name);
00984 
00985     f.xmlPushEnd();
00986 
00987     sint version = 2;
00988     version = f.serialVersion (version);
00989     string check = "REGION";
00990     f.serialCheck (check);
00991 
00992     f.xmlPush ("POINTS");
00993         f.serialCont (VPoints);
00994     f.xmlPop ();
00995     f.xmlPush ("PATHES");
00996         f.serialCont (VPaths);
00997     f.xmlPop ();
00998     f.xmlPush ("ZONES");
00999         f.serialCont (VZones);
01000     f.xmlPop ();
01001 
01002     if (version > 1)
01003     {
01004         f.xmlPush ("HIDEPOINTS");
01005             f.serialCont (VHidePoints);
01006         f.xmlPop ();
01007         f.xmlPush ("HIDEZONES");
01008             f.serialCont (VHideZones);
01009         f.xmlPop ();
01010         f.xmlPush ("HIDEPATHS");
01011             f.serialCont (VHidePaths);
01012         f.xmlPop ();
01013     }
01014     else
01015     {
01016         VHidePoints.resize  (VPoints.size(), false);
01017         VHideZones.resize   (VZones.size(), false);
01018         VHidePaths.resize   (VPaths.size(), false);
01019     }
01020 }
01021 
01022 // ***************************************************************************
01023 // IPrimitive
01024 // ***************************************************************************
01025 
01026 IPrimitive::IPrimitive ()
01027 {
01028     _Parent = NULL;
01029 }
01030 
01031 
01032 IPrimitive::IPrimitive (const IPrimitive &node) : IStreamable()
01033 {
01034     _Parent = NULL;
01035     IPrimitive::operator= (node);
01036 }
01037 
01038 // ***************************************************************************
01039 
01040 void IPrimitive::serial (NLMISC::IStream &f)
01041 {
01042     // NB : unparsed parameters are not binary serialized !
01043 
01044     // serialize the property container
01045     if (f.isReading())
01046     {
01047         uint32 size;
01048         f.serial(size);
01049         for (uint i=0; i<size; ++i)
01050         {
01051             std::string s;
01052             f.serial(s);
01053             IProperty *&pp = _Properties[s];
01054             f.serialPolyPtr(pp);
01055         }
01056     }
01057     else
01058     {
01059         uint32 size = _Properties.size();
01060         f.serial(size);
01061         std::map<std::string, IProperty*>::iterator first(_Properties.begin()), last(_Properties.end());
01062         for (; first != last; ++first)
01063         {
01064             std::string &s = const_cast<std::string&>(first->first);
01065 
01066             f.serial(s);
01067             f.serialPolyPtr(first->second);
01068         }
01069     }
01070     f.serial(_ChildId);
01071 
01072 //  f.serial(Layer);
01073 //  f.serial(Name);
01074 //  f.serial(Expanded);
01075 
01076     // serial the childrens
01077     if (f.isReading())
01078     {
01079         std::vector<IPrimitive*> children;
01080         f.serialContPolyPtr(children);
01081         uint index = 0;
01082         for(std::vector<IPrimitive*>::iterator it = children.begin(); it != children.end(); ++it, ++index)
01083         {
01084             insertChild(*it, index);
01085         }
01086     }
01087     else
01088     {
01089         f.serialContPolyPtr(_Children);
01090     }
01091 
01092     if (f.isReading())
01093     {
01094         // reloc child link
01095         vector<IPrimitive*>::iterator first(_Children.begin()), last(_Children.end());
01096         for (; first != last; ++first)
01097         {
01098             if (*first)
01099                 (*first)->_Parent = this;
01100         }
01101     }
01102 }
01103 
01104 
01105 // ***************************************************************************
01106 
01107 void IPrimitive::updateChildId (uint index)
01108 {
01109     uint i;
01110     uint count = _Children.size ();
01111     for (i=index; i<count; i++)
01112         _Children[i]->_ChildId = i;
01113 }
01114 
01115 // ***************************************************************************
01116 
01117 void IPrimitive::branchLink()
01118 {
01119     onBranchLink();
01120     std::vector<IPrimitive*>::iterator first(_Children.begin()), last(_Children.end());
01121     for (; first != last; ++first)
01122     {
01123         (*first)->branchLink();
01124     }
01125 }
01126 
01127 // ***************************************************************************
01128 
01129 void IPrimitive::branchUnlink()
01130 {
01131     onBranchUnlink();
01132     std::vector<IPrimitive*>::iterator first(_Children.begin()), last(_Children.end());
01133     for (; first != last; ++first)
01134     {
01135         (*first)->branchUnlink();
01136     }
01137 }
01138 
01139 
01140 // ***************************************************************************
01141 
01142 void IPrimitive::operator= (const IPrimitive &node)
01143 {
01144     // Clean dest
01145     removeChildren ();
01146     removeProperties ();
01147 
01148     // copy deprecated param
01149 //  Layer = node.Layer;
01150 //  Name = node.Name;
01151 
01152     // copy unparsed properties
01153     _UnparsedProperties = node._UnparsedProperties;
01154 
01155     // Copy the flags
01156 //  Expanded = node.Expanded;
01157     _ChildId = node._ChildId;
01158 
01159     // Copy children
01160     _Children.resize (node._Children.size ());
01161     for (uint child = 0; child < node._Children.size (); child++)
01162     {
01163         // Copy the child
01164         _Children[child] = node._Children[child]->copy ();
01165 
01166         // Set the parent
01167         _Children[child]->_Parent = this;
01168     }
01169 
01170     // Copy properties
01171     std::map<std::string, IProperty*>::const_iterator ite = node._Properties.begin ();
01172     while (ite != node._Properties.end ())
01173     {
01174         // Get the property
01175         CPropertyString *propString = dynamic_cast<CPropertyString *>(ite->second);
01176         if (propString)
01177         {
01178             // New property
01179             CPropertyString *newProp = new CPropertyString ();
01180             *newProp = *propString;
01181             _Properties.insert (std::map<std::string, IProperty*>::value_type (ite->first, newProp));
01182         }
01183         else
01184         {
01185             CPropertyStringArray *propStringArray = dynamic_cast<CPropertyStringArray *>(ite->second);
01186             if (propStringArray)
01187             {
01188                 // New property
01189                 CPropertyStringArray *newProp = new CPropertyStringArray ();
01190                 *newProp = *propStringArray;
01191                 _Properties.insert (std::map<std::string, IProperty*>::value_type (ite->first, newProp));
01192             }
01193             else
01194             {
01195                 CPropertyColor *propColor = dynamic_cast<CPropertyColor *>(ite->second);
01196                 nlverify (propColor);
01197 
01198                 // New property
01199                 CPropertyColor *newProp = new CPropertyColor ();
01200                 *newProp = *propColor;
01201                 _Properties.insert (std::map<std::string, IProperty*>::value_type (ite->first, newProp));
01202             }
01203         }
01204 
01205         ite++;
01206     }
01207 
01208 #ifdef NLLIGO_DEBUG
01209     _DebugClassName = node._DebugClassName;
01210     _DebugPrimitiveName = node._DebugPrimitiveName;
01211 #endif
01212 }
01213 
01214 
01215 const   IPrimitive  *IPrimitive::getPrimitive   (const  std::string &absoluteOrRelativePath)    const
01216 {
01217     const   IPrimitive  *cursor=this;
01218     string  path=absoluteOrRelativePath;
01219 
01220     if (path.find("//")==0) //  an absolute path.
01221     {
01222         while (cursor->getParent())
01223             cursor=cursor->getParent();
01224         path.erase(0,2);
01225     }
01226 
01227     while (path.size()>0)
01228     {
01229         if  (path.find("/")==0)
01230         {
01231             path.erase(0,1);
01232             continue;
01233         }
01234         if  (path.find("..")==0)
01235         {
01236             cursor=cursor->getParent();
01237             if  (!cursor)
01238                 return  NULL;
01239 
01240             path.erase(0,2);
01241             continue;
01242         }
01243 
01244         string::size_type indexStr=path.find("/");
01245         string            childName;
01246         if (indexStr==string::npos)
01247         {
01248             childName=path;
01249             path="";
01250         }
01251         else
01252         {
01253             childName=path.substr(0,indexStr);
01254             path.erase(0, indexStr);
01255         }
01256         childName=toUpper(childName);
01257         const   IPrimitive*child=NULL;
01258         uint    childIndex;
01259         for (childIndex=0;childIndex<cursor->getNumChildren();childIndex++)
01260         {
01261             cursor->getChild(child,childIndex);
01262             string  name;
01263             if  (   child->getPropertyByName("class", name)
01264                 &&  toUpper(name)==childName    )
01265                 break;
01266         }
01267         if  (childIndex>=cursor->getNumChildren())
01268             return  NULL;
01269 
01270         cursor=child;
01271     }
01272     return  cursor;
01273 }
01274 
01275 // ***************************************************************************
01276 
01277 bool IPrimitive::getProperty (uint index, std::string &property_name, const IProperty *&result) const
01278 {
01279     // Look for the property
01280     std::map<std::string, IProperty*>::const_iterator ite = _Properties.begin ();
01281     while (ite != _Properties.end ())
01282     {
01283         if (index == 0)
01284         {
01285             property_name = ite->first;
01286             result = ite->second;
01287             return true;
01288         }
01289         index--;
01290         ite ++;
01291     }
01292     nlwarning ("NLLIGO::IPrimitive::getProperty : invalid index (index : %d, size : %d).", index, _Properties.size ());
01293     return false;
01294 }
01295 
01296 // ***************************************************************************
01297 
01298 bool IPrimitive::getProperty (uint index, std::string &property_name, IProperty *&result)
01299 {
01300     // Look for the property
01301     std::map<std::string, IProperty*>::iterator ite = _Properties.begin ();
01302     while (ite != _Properties.end ())
01303     {
01304         if (index == 0)
01305         {
01306             property_name = ite->first;
01307             result = ite->second;
01308             return true;
01309         }
01310         index--;
01311         ite ++;
01312     }
01313     nlwarning ("NLLIGO::IPrimitive::getProperty : invalid index (index : %d, size : %d).", index, _Properties.size ());
01314     return false;
01315 }
01316 
01317 // ***************************************************************************
01318 
01319 bool IPrimitive::getPropertyByName (const char *property_name, const IProperty *&result) const
01320 {
01321     // Look for the property
01322     std::map<std::string, IProperty*>::const_iterator ite = _Properties.find (property_name);
01323     if (ite != _Properties.end ())
01324     {
01325         result = ite->second;
01326         return true;
01327     }
01328     return false;
01329 }
01330 
01331 // ***************************************************************************
01332 
01333 bool IPrimitive::getPropertyByName (const char *property_name, IProperty *&result) const
01334 {
01335     // Look for the property
01336     std::map<std::string, IProperty*>::const_iterator ite = _Properties.find (property_name);
01337     if (ite != _Properties.end ())
01338     {
01339         result = ite->second;
01340         return true;
01341     }
01342     return false;
01343 }
01344 
01345 // ***************************************************************************
01346 
01347 bool IPrimitive::getPropertyByName (const char *property_name, std::string *&result) const
01348 {
01349     // Get the property
01350     IProperty *prop;
01351     if (getPropertyByName (property_name, prop))
01352     {
01353         CPropertyString *strProp = dynamic_cast<CPropertyString *> (prop);
01354         if (strProp)
01355         {
01356             result = &(strProp->String);
01357             return true;
01358         }
01359         else
01360         {
01361             nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name);
01362         }
01363     }
01364     return false;
01365 }
01366 
01367 // ***************************************************************************
01368 
01369 bool IPrimitive::getPropertyByName (const char *property_name, std::string &result) const
01370 {
01371     // Get the property
01372     const IProperty *prop;
01373     if (getPropertyByName (property_name, prop))
01374     {
01375         const CPropertyString *strProp = dynamic_cast<const CPropertyString *> (prop);
01376         if (strProp)
01377         {
01378             result = strProp->String;
01379             return true;
01380         }
01381         else
01382         {
01383             nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name);
01384         }
01385     }
01386     return false;
01387 }
01388 
01389 // ***************************************************************************
01390 
01391 bool IPrimitive::getPropertyByName (const char *property_name, std::vector<std::string> *&result) const
01392 {
01393     // Get the property
01394     IProperty *prop;
01395     if (getPropertyByName (property_name, prop))
01396     {
01397         CPropertyStringArray *strProp = dynamic_cast<CPropertyStringArray *> (prop);
01398         if (strProp)
01399         {
01400             result = &(strProp->StringArray);
01401             return true;
01402         }
01403         else
01404         {
01405             nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name);
01406         }
01407     }
01408     return false;
01409 }
01410 
01411 // ***************************************************************************
01412 
01413 bool IPrimitive::getPropertyByName (const char *property_name, const std::vector<std::string> *&result) const
01414 {
01415     // Get the property
01416     IProperty *prop;
01417     if (getPropertyByName (property_name, prop))
01418     {
01419         const CPropertyStringArray *strProp = dynamic_cast<const CPropertyStringArray *> (prop);
01420         if (strProp)
01421         {
01422             result = &(strProp->StringArray);
01423             return true;
01424         }
01425         else
01426         {
01427             nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name);
01428         }
01429     }
01430     return false;
01431 }
01432 
01433 // ***************************************************************************
01434 
01435 bool IPrimitive::getPropertyByName (const char *property_name, NLMISC::CRGBA &result) const
01436 {
01437     // Get the property
01438     IProperty *prop;
01439     if (getPropertyByName (property_name, prop))
01440     {
01441         const CPropertyColor *colorProp = dynamic_cast<const CPropertyColor *> (prop);
01442         if (colorProp)
01443         {
01444             result = colorProp->Color;
01445             return true;
01446         }
01447         else
01448         {
01449             nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a color.", property_name);
01450         }
01451     }
01452     return false;
01453 }
01454 
01455 // ***************************************************************************
01456 
01457 bool IPrimitive::removeProperty (uint index)
01458 {
01459     // Look for the property
01460     std::map<std::string, IProperty*>::iterator ite = _Properties.begin ();
01461     while (ite != _Properties.end ())
01462     {
01463         if (index == 0)
01464         {
01465             _Properties.erase (ite);
01466             return true;
01467         }
01468         index--;
01469         ite ++;
01470     }
01471     nlwarning ("NLLIGO::IPrimitive::removeProperty : invalid index (index : %d, size : %d).", index, _Properties.size ());
01472     return false;
01473 }
01474 
01475 // ***************************************************************************
01476 
01477 bool IPrimitive::removePropertyByName (const char *property_name)
01478 {
01479     // Look for the property
01480     std::map<std::string, IProperty*>::iterator ite = _Properties.find (property_name);
01481     if (ite != _Properties.end ())
01482     {
01483         _Properties.erase (ite);
01484         return true;
01485     }
01486     return false;
01487 }
01488 
01489 // ***************************************************************************
01490 
01491 void IPrimitive::removeProperties ()
01492 {
01493     std::map<std::string, IProperty*>::iterator ite = _Properties.begin ();
01494     while (ite != _Properties.end ())
01495     {
01496         delete ite->second;
01497         ite++;
01498     }
01499     _Properties.clear ();
01500 }
01501 
01502 // ***************************************************************************
01503 
01504 bool IPrimitive::getChild (const IPrimitive *&result, uint childId) const
01505 {
01506     if (childId < _Children.size ())
01507     {
01508         result = _Children[childId];
01509         return true;
01510     }
01511     else
01512     {
01513         nlwarning ("NLLIGO::IPrimitive::getChild : invalid index (index : %d, size %d).", childId, _Children.size ());
01514     }
01515     return false;
01516 }
01517 
01518 // ***************************************************************************
01519 
01520 bool IPrimitive::getChild (IPrimitive *&result, uint childId)
01521 {
01522     if (childId < _Children.size ())
01523     {
01524         result = _Children[childId];
01525         return true;
01526     }
01527     else
01528     {
01529         nlwarning ("NLLIGO::IPrimitive::getChild : invalid index (index : %d, size %d).", childId, _Children.size ());
01530     }
01531     return false;
01532 }
01533 
01534 // ***************************************************************************
01535 
01536 bool IPrimitive::removeChild (IPrimitive *child)
01537 {
01538     uint childId;
01539     if (getChildId(childId, child))
01540     {
01541         return removeChild(childId);
01542     }
01543     else
01544     {
01545         nlwarning("NLLIGO::IPrimitive::removeChild : invalid child, can't remove (child : %p)", child);
01546     }
01547     return false;
01548 }
01549 
01550 // ***************************************************************************
01551 
01552 bool IPrimitive::removeChild (uint childId)
01553 {
01554     if (childId < _Children.size ())
01555     {
01556         delete _Children[childId];
01557         _Children.erase (_Children.begin()+childId);
01558         updateChildId (childId);
01559         return true;
01560     }
01561     else
01562     {
01563         nlwarning ("NLLIGO::IPrimitive::removeChild : invalid index (index : %d, size %d).", childId, _Children.size ());
01564     }
01565     return false;
01566 }
01567 
01568 // ***************************************************************************
01569 
01570 void IPrimitive::removeChildren ()
01571 {
01572     // Erase children
01573     for (uint i=0; i<_Children.size (); i++)
01574     {
01575         delete _Children[i];
01576     }
01577     _Children.clear ();
01578 }
01579 
01580 // ***************************************************************************
01581 
01582 bool IPrimitive::unlinkChild(IPrimitive *child)
01583 {
01584     uint childId;
01585     if (getChildId(childId, child))
01586     {
01587         child->onUnlinkFromParent();
01588         child->branchUnlink();
01589         _Children.erase (_Children.begin()+childId);
01590         updateChildId (childId);
01591         child->_Parent = NULL;
01592         child->_ChildId = 0;
01593         return true;
01594     }
01595     else
01596     {
01597         nlwarning("NLLIGO::IPrimitive::unlinkChild : invalid child, can't unlink (child : %p)", child);
01598     }
01599     return false;
01600 }
01601 
01602 // ***************************************************************************
01603 
01604 bool IPrimitive::insertChild (IPrimitive *primitive, uint index)
01605 {
01606     // At the end ?
01607     if (index == AtTheEnd)
01608         index = _Children.size ();
01609 
01610     // Index valid ?
01611     if (index>_Children.size ())
01612         return false;
01613 
01614     // Insert
01615     _Children.insert (_Children.begin () + index, primitive);
01616 
01617     // Update child id
01618     updateChildId (index);
01619 
01620     // Link to the parent
01621     primitive->_Parent = this;
01622 
01623     // signaling
01624     primitive->onLinkToParent();
01625     primitive->branchLink();
01626 
01627     return true;
01628 }
01629 
01630 // ***************************************************************************
01631 
01632 IPrimitive::~IPrimitive ()
01633 {
01634     // Remove children
01635     removeChildren ();
01636 
01637     // Erase properties
01638     removeProperties ();
01639 }
01640 
01641 // ***************************************************************************
01642 bool IPrimitive::checkProperty(const std::string &property_name) const
01643 {
01644     if (_Properties.find(property_name) == _Properties.end())
01645         return false;
01646     return true;
01647 }
01648 
01649 // ***************************************************************************
01650 
01651 bool IPrimitive::addPropertyByName (const char *property_name, IProperty *result)
01652 {
01653     bool inserted = _Properties.insert (std::map<std::string, IProperty*>::value_type (property_name, result)).second;
01654     if (inserted)
01655     {
01656         return true;
01657     }
01658     return false;
01659 }
01660 
01661 // ***************************************************************************
01662 
01663 bool IPrimitive::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)
01664 {
01665     // Erase old properties
01666     _Properties.clear ();
01667 
01668     // Read the unparsed properties (for editor view)
01669     xmlNodePtr commentNode = CIXml::getFirstChildNode(xmlNode, XML_COMMENT_NODE);
01670     if (commentNode)
01671     {
01672          if (!CIXml::getContentString(_UnparsedProperties, commentNode))
01673             _UnparsedProperties = "";
01674     }
01675 
01676     // Read the expanded flag
01677 //  string expanded;
01678 //  Expanded = true;
01679 //  if (CIXml::getPropertyString (expanded, xmlNode, "EXPANDED"))
01680 //      Expanded = (expanded != "false");
01681 
01682     // Read the properties
01683     xmlNodePtr propNode;
01684     propNode = CIXml::getFirstChildNode (xmlNode, "PROPERTY");
01685     if (propNode)
01686     {
01687         do
01688         {
01689             // Read the name
01690             string name;
01691             if (GetNodeString (name, filename, propNode, "NAME"))
01692             {
01693                 // Get the property type
01694                 string type;
01695                 if (GetPropertyString (type, filename, propNode, "TYPE"))
01696                 {
01697                     // The property
01698                     IProperty *property = NULL;
01699 
01700                     // Check the type
01701                     if (type == "string")
01702                     {
01703                         // Create a new property
01704                         CPropertyString *propertyString = new CPropertyString;
01705                         property = propertyString;
01706 
01707                         // Read it
01708                         if (!GetNodeString (propertyString->String, filename, propNode, "STRING"))
01709                         {
01710                             return false;
01711                         }
01712                     }
01713                     else if (type == "string_array")
01714                     {
01715                         // Create a new property
01716                         CPropertyStringArray *propertyStringArray = new CPropertyStringArray;
01717                         property = propertyStringArray;
01718 
01719                         // Read strings
01720                         xmlNodePtr stringNode;
01721                         propertyStringArray->StringArray.reserve (CIXml::countChildren (propNode, "STRING"));
01722                         stringNode = CIXml::getFirstChildNode (propNode, "STRING");
01723                         if (stringNode)
01724                         {
01725                             do
01726                             {
01727                                 // Add the string
01728                                 string content;
01729                                 GetContentString (content, filename, stringNode);
01730                                 propertyStringArray->StringArray.push_back (content);
01731 
01732                                 stringNode = CIXml::getNextChildNode (stringNode, "STRING");
01733                             }
01734                             while (stringNode);
01735                         }
01736                     }
01737                     else if (type == "color")
01738                     {
01739                         // Create a new property
01740                         CPropertyColor *propertyColor= new CPropertyColor;
01741                         property = propertyColor;
01742 
01743                         // Read strings
01744                         xmlNodePtr colorNode;
01745                         colorNode = CIXml::getFirstChildNode (xmlNode, "COLOR");
01746                         string R, G, B, A;
01747                         if (GetPropertyString (R, filename, colorNode, "R") &&
01748                             GetPropertyString (G, filename, colorNode, "G") &&
01749                             GetPropertyString (B, filename, colorNode, "B") &&
01750                             GetPropertyString (A, filename, colorNode, "A"))
01751                         {
01752                             sint32 sR=0, sG=0, sB=0, sA=255;
01753                             sR = atoi (R.c_str ());
01754                             clamp (sR, 0, 255);
01755                             sG = atoi (G.c_str ());
01756                             clamp (sG, 0, 255);
01757                             sB = atoi (B.c_str ());
01758                             clamp (sB, 0, 255);
01759                             sA = atoi (A.c_str ());
01760                             clamp (sR, 0, 255);
01761                             propertyColor->Color.R = (uint8)sR;
01762                             propertyColor->Color.G = (uint8)sG;
01763                             propertyColor->Color.B = (uint8)sB;
01764                             propertyColor->Color.A = (uint8)sA;
01765                         }
01766                         else
01767                             return false;
01768                     }
01769 
01770                     // Property found ?
01771                     if (property == NULL)
01772                     {
01773                         XMLError (propNode, filename, "IPrimitive::read : Unknown property type (%s)", type.c_str ());
01774                         return false;
01775                     }
01776 
01777                     // Add it
01778                     _Properties.insert (std::map<std::string, IProperty*>::value_type (name, property));
01779                 }
01780                 else
01781                 {
01782                     return false;
01783                 }
01784             }
01785             else
01786             {
01787                 return false;
01788             }
01789 
01790             propNode = CIXml::getNextChildNode (propNode, "PROPERTY");
01791         }
01792         while (propNode);
01793     }
01794 
01795     // Initialise default value
01796     initDefaultValues (config);
01797 
01798     // Read children
01799     xmlNodePtr childNode;
01800     childNode = CIXml::getFirstChildNode (xmlNode, "CHILD");
01801     if (childNode)
01802     {
01803         do
01804         {
01805             // Get the property class
01806             string type;
01807             if (GetPropertyString (type, filename, childNode, "TYPE"))
01808             {
01809                 // Primitive
01810                 if (type=="node")
01811                     type="CPrimNode";
01812                 if (type=="point")
01813                     type="CPrimPoint";
01814                 if (type=="path")
01815                     type="CPrimPath";
01816                 if (type=="zone")
01817                     type="CPrimZone";
01818                 if (type=="alias")
01819                     type="CPrimAlias";
01820                 IPrimitive *primitive = static_cast<IPrimitive *> (CClassRegistry::create (type));
01821 
01822                 // Primitive type not found ?
01823                 if (primitive == NULL)
01824                 {
01825                     XMLError (childNode, filename, "IPrimitive::read : Unknown primitive type (%s)", type.c_str ());
01826                     return false;
01827                 }
01828 
01829                 // Read it
01830                 primitive->read (childNode, filename, version, config);
01831 
01832                 // Add it
01833                 insertChild (primitive);
01834 
01835             }
01836             else
01837             {
01838                 return false;
01839             }
01840 
01841             childNode = CIXml::getNextChildNode (childNode, "CHILD");
01842         }
01843         while (childNode);
01844     }
01845 
01846 #ifdef NLLIGO_DEBUG
01847     // store debug data
01848     getPropertyByName("class", _DebugClassName);
01849     getPropertyByName("name", _DebugPrimitiveName);
01850 #endif
01851     // Done
01852     return true;
01853 }
01854 
01855 // ***************************************************************************
01856 
01857 void IPrimitive::initDefaultValues (CLigoConfig &config)
01858 {
01859     // Get the primitive class
01860     const CPrimitiveClass *primitiveClass = config.getPrimitiveClass (*this);
01861     if (primitiveClass)
01862     {
01863         // For each properties
01864         uint count = primitiveClass->Parameters.size ();
01865         uint i;
01866         for (i=0; i<count; i++)
01867         {
01868             const CPrimitiveClass::CParameter &parameter = primitiveClass->Parameters[i];
01869 
01870             // Get the property
01871             IProperty *result;
01872             if (!getPropertyByName (parameter.Name.c_str(), result))
01873             {
01874                 // Create the property
01875                 if ((parameter.Type == CPrimitiveClass::CParameter::StringArray) || (parameter.Type == CPrimitiveClass::CParameter::ConstStringArray))
01876                     result = new CPropertyStringArray();
01877                 else
01878                     result = new CPropertyString();
01879                 nlverify (addPropertyByName (parameter.Name.c_str(), result));
01880             }
01881         }
01882 
01883         // Set the default values
01884         for (i=0; i<count; i++)
01885         {
01886             const CPrimitiveClass::CParameter &parameter = primitiveClass->Parameters[i];
01887 
01888             CPropertyString *pString = NULL;
01889             CPropertyStringArray *pStringArray = NULL;
01890 
01891             IProperty *result;
01892             nlverify (getPropertyByName (parameter.Name.c_str(), result));
01893             pString = dynamic_cast<CPropertyString*>(result);
01894             if (!pString)
01895                 pStringArray = dynamic_cast<CPropertyStringArray*>(result);
01896 
01897             // Property have default values ?
01898             if (pString)
01899             {
01900                 // Empty string ?
01901                 if (pString->String.empty())
01902                 {
01903                     // Set as default
01904                     pString->Default = true;
01905                     parameter.getDefaultValue (pString->String, *this, *primitiveClass);
01906                 }
01907             }
01908             else if (pStringArray)
01909             {
01910                 // Empty string array ?
01911                 if (pStringArray->StringArray.empty())
01912                 {
01913                     // Set as default
01914                     pStringArray->Default = true;
01915                     parameter.getDefaultValue (pStringArray->StringArray, *this, *primitiveClass);
01916                 }
01917             }
01918         }
01919     }
01920 }
01921 
01922 // ***************************************************************************
01923 
01924 void IPrimitive::write (xmlNodePtr xmlNode, const char *filename) const
01925 {
01926     // Save the expanded flag
01927 //  if (!Expanded)
01928 //      xmlSetProp (xmlNode, (const xmlChar*)"EXPANDED", (const xmlChar*)"false");
01929 
01930     // Set the type
01931     xmlSetProp (xmlNode, (const xmlChar*)"TYPE", (const xmlChar*)(const_cast<IPrimitive*> (this)->getClassName ().c_str ()));
01932 
01933     // Save the unparsed property
01934     if (!_UnparsedProperties.empty())
01935     {
01936         xmlNodePtr commentNode = xmlNewComment((const xmlChar*)(_UnparsedProperties.c_str()));
01937         nlverify(commentNode);
01938         xmlAddChild(xmlNode, commentNode);
01939     }
01940 
01941     // Save the properties
01942     std::map<std::string, IProperty*>::const_iterator ite = _Properties.begin ();
01943     while (ite != _Properties.end ())
01944     {
01945         // Not a default property ?
01946         if (!ite->second->Default)
01947         {
01948             // Create new nodes
01949             xmlNodePtr propNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"PROPERTY", NULL);
01950             xmlNodePtr nameNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"NAME", NULL);
01951             xmlNodePtr textNode = xmlNewText ((const xmlChar *)(ite->first.c_str ()));
01952             xmlAddChild (nameNode, textNode);
01953 
01954             // Type
01955             const CPropertyString *str = dynamic_cast<const CPropertyString *> (ite->second);
01956             if (str)
01957             {
01958                 // Set the type
01959                 xmlSetProp (propNode, (const xmlChar*)"TYPE", (const xmlChar*)"string");
01960 
01961                 // Create new nodes
01962                 xmlNodePtr stringNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"STRING", NULL);
01963                 xmlNodePtr textNode = xmlNewText ((const xmlChar *)(str->String.c_str ()));
01964                 xmlAddChild (stringNode, textNode);
01965             }
01966             else
01967             {
01968                 // Should be an array
01969                 const CPropertyStringArray *array = dynamic_cast<const CPropertyStringArray *> (ite->second);
01970                 if (array)
01971                 {
01972                     // Set the type
01973                     xmlSetProp (propNode, (const xmlChar*)"TYPE", (const xmlChar*)"string_array");
01974 
01975                     // For each strings in the array
01976                     for (uint i=0; i<array->StringArray.size (); i++)
01977                     {
01978                         // Create new nodes
01979                         xmlNodePtr stringNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"STRING", NULL);
01980                         xmlNodePtr textNode = xmlNewText ((const xmlChar *)(array->StringArray[i].c_str ()));
01981                         xmlAddChild (stringNode, textNode);
01982                     }
01983                 }
01984                 else
01985                 {
01986                     // Should be a color
01987                     const CPropertyColor *color = safe_cast<const CPropertyColor *> (ite->second);
01988 
01989                     // Set the type
01990                     xmlSetProp (propNode, (const xmlChar*)"TYPE", (const xmlChar*)"color");
01991 
01992                     // Create new nodes
01993                     xmlNodePtr colorNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"COLOR", NULL);
01994                     xmlSetProp (colorNode, (const xmlChar*)"R", (const xmlChar*)toString (color->Color.R).c_str ());
01995                     xmlSetProp (colorNode, (const xmlChar*)"G", (const xmlChar*)toString (color->Color.G).c_str ());
01996                     xmlSetProp (colorNode, (const xmlChar*)"B", (const xmlChar*)toString (color->Color.B).c_str ());
01997                     xmlSetProp (colorNode, (const xmlChar*)"A", (const xmlChar*)toString (color->Color.A).c_str ());
01998                 }
01999             }
02000         }
02001 
02002         ite++;
02003     }
02004 
02005     // Save the children
02006     for (uint i=0; i<_Children.size (); i++)
02007     {
02008         // New node
02009         xmlNodePtr childNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"CHILD", NULL);
02010 
02011         // Write it
02012         _Children[i]->write (childNode, filename);
02013     }
02014 }
02015 
02016 // ***************************************************************************
02017 
02018 bool IPrimitive::getChildId (uint &childId, const IPrimitive *child) const
02019 {
02020     childId = child->_ChildId;
02021     return true;
02022 }
02023 
02024 // ***************************************************************************
02025 
02026 uint IPrimitive::getNumProperty () const
02027 {
02028     return _Properties.size ();
02029 }
02030 
02031 // ***************************************************************************
02032 
02033 std::string     IPrimitive::getName() const
02034 {
02035     std::string ret;
02036     getPropertyByName("name", ret);
02037     return ret;
02038 }
02039 
02040 // ***************************************************************************
02041 
02042 const std::string &IPrimitive::getUnparsedProperties() const
02043 {
02044     return _UnparsedProperties;
02045 }
02046 
02047 // ***************************************************************************
02048 
02049 void IPrimitive::setUnparsedProperties(const std::string &unparsedProperties) const
02050 {
02051     _UnparsedProperties = unparsedProperties;
02052 }
02053 
02054 // ***************************************************************************
02055 // CPrimAlias
02056 // ***************************************************************************
02057 
02058 CPrimAlias::CPrimAlias() :
02059     _Alias(0),
02060     _Container(NULL)
02061 {
02062 }
02063 
02064 CPrimAlias::CPrimAlias(const CPrimAlias &other)
02065     : IPrimitive(other)
02066 {
02067     // clear the container reference and alias
02068     _Container = NULL;
02069     _Alias = other._Alias;
02070 }
02071 
02072 CPrimAlias::~CPrimAlias()
02073 {
02074     if (_Container)
02075         onBranchUnlink();
02076 }
02077 
02078 void CPrimAlias::onBranchLink()
02079 {
02080     CPrimitiveContext   &ctx = CPrimitiveContext::instance();
02081     // context must be set when handling alias
02082     nlassert(ctx.CurrentPrimitive);
02083     nlassert(_Container ==  NULL || _Container == ctx.CurrentPrimitive);
02084 
02085     _Container = ctx.CurrentPrimitive;
02086 
02087     // generate a new alias, eventually keeping the current one if any and if still available
02088     _Alias = _Container->genAlias(this, _Alias);
02089 }
02090 
02091 void CPrimAlias::onBranchUnlink()
02092 {
02093     nlassert(_Container !=  NULL);
02094     _Container->releaseAlias(this, _Alias);
02095     _Container = NULL;
02096 
02097     // NB : we keep the alias value for next linkage
02098 }
02099 
02100 uint32  CPrimAlias::getAlias() const
02101 {
02102     return _Alias;
02103 }
02104 
02105 uint32  CPrimAlias::getFullAlias() const
02106 {
02107     nlassert(_Container != NULL);
02108     return _Container->buildFullAlias(_Alias);
02109 }
02110 
02111 void CPrimAlias::regenAlias()
02112 {
02113     // container must exist
02114     nlassert(_Container);
02115     // generate a new alias, eventually keeping the current one if any and if still available
02116     _Alias = _Container->genAlias(this, _Alias);
02117 }
02118 
02119 
02120 // Read the primitive
02121 bool CPrimAlias::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)
02122 {
02123     // Read alias
02124     xmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, "ALIAS");
02125     if (ptNode)
02126     {
02127         int val;
02128         if (ReadInt ("VALUE", val, filename, ptNode))
02129         {
02130             _Alias = uint32(val);
02131 
02132 //          nlassert( CPrimitiveContext::instance().CurrentPrimitive);
02134 //           CPrimitiveContext::instance().CurrentPrimitive->reserveAlias(_Alias);
02135 //          // set to null, it will be rewrited by onBranchLink callback
02137         }
02138         else
02139         {
02140             // error in format !
02141             nlwarning("CPrimAlias::read: Can't find xml property 'VALUE' in element <ALIAS>");
02142             return false;
02143         }
02144     }
02145     else
02146     {
02147         // error in format !
02148         nlwarning("CPrimAlias::read: Can't find xml element <ALIAS>");
02149         return false;
02150     }
02151 
02152     return IPrimitive::read (xmlNode, filename, version, config);
02153 }
02154 // Write the primitive
02155 void CPrimAlias::write (xmlNodePtr xmlNode, const char *filename) const
02156 {
02157     // Write alias
02158     xmlNodePtr ptNode = xmlNewChild(xmlNode, NULL, (const xmlChar*)"ALIAS", NULL);
02159     WriteInt("VALUE", int(_Alias), ptNode);
02160 
02161     IPrimitive::write (xmlNode, filename);
02162 }
02163 
02164 // Create a copy of this primitive
02165 IPrimitive *CPrimAlias::copy () const
02166 {
02167     // NB : this will not call the reserveAlias on the container
02168     CPrimAlias *pa = new CPrimAlias(*this);
02169 
02170     // clear the alias and container reference
02171 //  pa->_Alias = 0;
02172 //  pa->_Container = 0;
02173 
02174     return pa;
02175 }
02176 // serial for binary save
02177 void CPrimAlias::serial (NLMISC::IStream &f)
02178 {
02179     IPrimitive::serial(f);
02180 
02181     f.serial(_Alias);
02182 
02183 //  if (f.isReading())
02184 //  {
02185 //      nlassert(_Container);
02186 //      _Container->reserveAlias(_Alias);
02187 //  }
02188 }
02189 
02190 
02191 // ***************************************************************************
02192 // CPrimitives
02193 // ***************************************************************************
02194 
02195 CPrimitives::CPrimitives () :
02196     _LigoConfig(NULL)
02197 {
02198     // init the alias generator
02199     _LastGeneratedAlias = 0;
02200     _AliasStaticPart = 0;
02201 
02202     RootNode = static_cast<CPrimNode *> (CClassRegistry::create ("CPrimNode"));
02203 
02204     // get the current ligo context (if any)
02205     _LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig;
02206 }
02207 
02208 // ***************************************************************************
02209 
02210 CPrimitives::CPrimitives (const CPrimitives &other)
02211 {
02212     operator =(other);
02213 //  _LastGeneratedAlias = other._LastGeneratedAlias;
02214 //  // get the current ligo context (if any)
02215 //  _LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig;
02216 //
02217 //  CPrimitives *temp = CPrimitiveContext::instance().CurrentPrimitive;
02218 //  CPrimitiveContext::instance().CurrentPrimitive = this;
02219 //  // copy the nodes
02220 //  RootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());
02221 //  RootNode->branchLink();
02222 //
02223 //  CPrimitiveContext::instance().CurrentPrimitive = temp;
02224 }
02225 
02226 // ***************************************************************************
02227 
02228 CPrimitives::~CPrimitives ()
02229 {
02230     delete RootNode;
02231 }
02232 
02233 // ***************************************************************************
02234 
02235 uint32 CPrimitives::getAliasStaticPart()
02236 {
02237     return _AliasStaticPart;
02238 }
02239 
02240 // ***************************************************************************
02241 
02242 void CPrimitives::setAliasStaticPart(uint32 staticPart)
02243 {
02244     _AliasStaticPart = staticPart;
02245 }
02246 
02247 // ***************************************************************************
02248 
02249 uint32 CPrimitives::buildFullAlias(uint32 dynamicPart)
02250 {
02251     if (_LigoConfig)
02252     {
02253         return _LigoConfig->buildAlias(_AliasStaticPart, dynamicPart, true);
02254     }
02255     else
02256         return dynamicPart;
02257 }
02258 
02259 
02260 // ***************************************************************************
02261 
02262 uint32 CPrimitives::genAlias(IPrimitive *prim, uint32 preferedAlias)
02263 {
02264     nlassert(_LigoConfig);
02265     uint32 ret;
02266 
02267     if (preferedAlias != 0)
02268     {
02269         // only dynamic part allowed here
02270         nlassert(preferedAlias == (preferedAlias & _LigoConfig->getDynamicAliasMask()));
02271         // check is the prefered alias is not already in use
02272         map<uint32, IPrimitive*>::iterator it(_AliasInUse.find(preferedAlias));
02273         if (it == _AliasInUse.end())
02274         {
02275             // this alias is available, just use it
02276 //          nldebug("Alias: added alias %u, %u alias used", preferedAlias, _AliasInUse.size()+1);
02277             _AliasInUse.insert(make_pair(preferedAlias, prim));
02278             return preferedAlias;
02279         }
02280         else
02281         {
02282             // check who own the alias now
02283             if (it->second == prim)
02284             {
02285                 // ok, the alias is already own by this primitive
02286 //              nldebug("Alias: using alias %u, %u alias used", preferedAlias, _AliasInUse.size()+1);
02287                 return preferedAlias;
02288             }
02289         }
02290     }
02291 
02292     // make sure there are some free aliases
02293     uint32 mask = _LigoConfig->getDynamicAliasMask();
02294     nlassert(_AliasInUse.size() < mask);
02295 
02296     // increment alias counter
02297     ++_LastGeneratedAlias;
02298     // mask with the dynamic alias mask
02299     _LastGeneratedAlias &= _LigoConfig->getDynamicAliasMask();
02300 
02301     ret = _LastGeneratedAlias;
02302 
02303     while (_AliasInUse.find(ret) != _AliasInUse.end())
02304     {
02305         // this alias is already in use ! generate a new one
02306         // increment, mask, affect...
02307         ++_LastGeneratedAlias;
02308         _LastGeneratedAlias &= _LigoConfig->getDynamicAliasMask();
02309         ret = _LastGeneratedAlias;
02310     }
02311 
02312     // insert the alias
02313 //  nldebug("Alias: added alias %u, %u alias in use", ret, _AliasInUse.size()+1);
02314     _AliasInUse.insert(make_pair(ret, prim));
02315 
02316     // callback
02317     prim->onModifyPrimitive (*this);
02318 
02319     return ret;
02320 }
02321 
02322 //void CPrimitives::reserveAlias(uint32 dynamicAlias)
02323 //{
02324 //  // need ligo config
02325 //  nlassert(_LigoConfig);
02326 //  // only dynamic part allowed here
02327 //  nlassert(dynamicAlias == (dynamicAlias & _LigoConfig->getDynamicAliasMask()));
02328 //  std::set<uint32>::iterator it(_AliasInUse.find(dynamicAlias));
02329 //  // warn if already found
02330 //  if (it != _AliasInUse.end())
02331 //  {
02332 //      const string &fileName = _LigoConfig->getFileNameForStaticAlias(_AliasStaticPart);
02333 //      if (fileName.empty())
02334 //          nlwarning("Dynamic Alias %u is already in use");
02335 //      else
02336 //          nlwarning("Dynamic Alias %u is already in use in file '%s'",
02337 //              dynamicAlias,
02338 //              fileName.c_str());
02339 //      return;
02340 //  }
02341 //
02342 //  // insert the alias
02343 //  nldebug("Alias: added alias %u, %u alias in use", dynamicAlias, _AliasInUse.size()+1);
02344 //  _AliasInUse.insert(dynamicAlias);
02345 //}
02346 //
02347 void CPrimitives::releaseAlias(IPrimitive *prim, uint32 alias)
02348 {
02349     // need ligo config
02350     nlassert(_LigoConfig);
02351     // only dynamic part allowed here
02352     nlassert(alias == (alias & _LigoConfig->getDynamicAliasMask()));
02353     std::map<uint32, IPrimitive*>::iterator it(_AliasInUse.find(alias));
02354     // need to be found
02355     nlassert(it != _AliasInUse.end());
02356 
02357     if (it->second != prim)
02358     {
02359         nlwarning("CPrimitives::releaseAlias: The alias %u is own by another primitive !", alias);
02360         return;
02361     }
02362 
02363     // remove this alias
02364 //  nldebug("Alias: remove alias %u, %u alias left", it->first, _AliasInUse.size()-1);
02365     _AliasInUse.erase(it);
02366 }
02367 
02368 // ***************************************************************************
02369 
02370 void CPrimitives::forceAlias(CPrimAlias *prim, uint32 alias)
02371 {
02372     // need ligo config
02373     nlassert(_LigoConfig);
02374     // only dynamic part allowed here
02375     nlassert(alias == (alias & _LigoConfig->getDynamicAliasMask()));
02376 
02377     // store the alias in the primitive
02378     prim->_Alias = alias;
02379 
02380     std::map<uint32, IPrimitive*>::iterator it(_AliasInUse.find(alias));
02381     if (it != _AliasInUse.end() && it->second != prim)
02382     {
02383         // we need to alloc and set a new alias for the current alias holder
02384         CPrimAlias *pa = static_cast<CPrimAlias*>(const_cast<IPrimitive*>(it->second));
02385 
02386         // reserve the alias for the new primitive
02387         it->second = prim;
02388 
02389 
02390         // and regen an alias for the old
02391         pa->regenAlias();
02392     }
02393     else
02394     {
02395         // just store the association
02396         _AliasInUse.insert(make_pair(alias, prim));
02397     }
02398 
02399 }
02400 
02401 // ***************************************************************************
02402 
02403 uint32 CPrimitives::getLastGeneratedAlias()
02404 {
02405     return _LastGeneratedAlias;
02406 }
02407 
02408 // ***************************************************************************
02409 
02410 IPrimitive      *CPrimitives::getPrimitiveByAlias(uint32 primAlias)
02411 {
02412     // check the static part of the alias
02413     uint32 staticAlias = _LigoConfig->getStaticAliasMask() & primAlias;
02414     staticAlias = staticAlias >> _LigoConfig->getDynamicAliasSize();
02415     if (staticAlias != _AliasStaticPart)
02416         return NULL;
02417 
02418     // clear the static part before searching
02419     primAlias &= _LigoConfig->getDynamicAliasMask();
02420 
02421     std::map<uint32, IPrimitive*>::const_iterator it(_AliasInUse.find(primAlias));
02422 
02423     if (it != _AliasInUse.end())
02424         return it->second->getParent();
02425     else
02426         return NULL;
02427 }
02428 
02429 // ***************************************************************************
02430 
02431 void        CPrimitives::buildPrimitiveWithAliasList(std::map<uint32, IPrimitive*> &result)
02432 {
02433     nlassert(_LigoConfig != NULL);
02434 
02435     std::map<uint32, IPrimitive*>::iterator first(_AliasInUse.begin()), last(_AliasInUse.end());
02436     for (; first != last; ++first)
02437     {
02438         result.insert(make_pair(_LigoConfig->buildAlias(_AliasStaticPart, first->first), first->second->getParent()));
02439     }
02440 }
02441 
02442 // ***************************************************************************
02443 
02444 CPrimitives& CPrimitives::operator= (const CPrimitives &other)
02445 {
02446 //  RootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());
02447 //  return *this;
02448 
02449     _AliasStaticPart = other._AliasStaticPart;
02450     _LastGeneratedAlias = other._LastGeneratedAlias;
02451     // get the current ligo context (if any)
02452     _LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig;
02453 
02454     CPrimitives *temp = CPrimitiveContext::instance().CurrentPrimitive;
02455     CPrimitiveContext::instance().CurrentPrimitive = this;
02456     // copy the nodes
02457     RootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());
02458     RootNode->branchLink();
02459 
02460     CPrimitiveContext::instance().CurrentPrimitive = temp;
02461 
02462     return *this;
02463 }
02464 
02465 // ***************************************************************************
02466 
02467 bool CPrimitives::read (xmlNodePtr xmlNode, const char *filename, CLigoConfig &config)
02468 {
02469     nlassert (xmlNode);
02470 
02471     _Filename = CFile::getFilename(filename);
02472     if (_LigoConfig)
02473     {
02474         // try to get the static alias mapping
02475         _AliasStaticPart = _LigoConfig->getFileStaticAliasMapping(CFile::getFilename(filename));
02476     }
02477 
02478     // Clear the primitives
02479     RootNode->removeChildren ();
02480     RootNode->removeProperties ();
02481 
02482     // Get the name
02483     if (strcmp ((const char*)xmlNode->name, "PRIMITIVES") == 0)
02484     {
02485         // Get the version
02486         string versionName = "0";
02487         if (GetPropertyString (versionName, filename, xmlNode, "VERSION"))
02488         {
02489             // Get the version
02490             uint32 version = atoi (versionName.c_str ());
02491 
02492             // Check the version
02493             if (version <= NLLIGO_PRIMITIVE_VERSION)
02494             {
02495                 // Read the primitives
02496                 xmlNode = GetFirstChildNode (xmlNode, filename, "ROOT_PRIMITIVE");
02497                 if (xmlNode)
02498                 {
02499                     if (version > 0)
02500                     {
02501                         xmlNodePtr subNode = GetFirstChildNode(xmlNode, filename, "ALIAS");
02502                         if (subNode)
02503                         {
02504                             uint temp;
02505                             ReadUInt("LAST_GENERATED", temp, filename, subNode);
02506                             _LastGeneratedAlias = temp;
02507                         }
02508                         else
02509                             _LastGeneratedAlias = 0;
02510                     }
02511                     else
02512                         _LastGeneratedAlias = 0;
02513 
02514                     // Read the primitive tree
02515                     ((IPrimitive*)RootNode)->read (xmlNode, filename, version, config);
02516                 }
02517             }
02518             else
02519             {
02520                 Error (filename, "CPrimitives::read : Unknown file version (%d)", version);
02521                 return false;
02522             }
02523         }
02524         else
02525         {
02526             return false;
02527         }
02528     }
02529     else
02530     {
02531         XMLError (xmlNode, filename, "This XML document is not a NeL primitive file");
02532         return false;
02533     }
02534 
02535     return true;
02536 }
02537 
02538 // ***************************************************************************
02539 
02540 void CPrimitives::write (xmlDocPtr doc, const char *filename) const
02541 {
02542     nlassert (doc);
02543 
02544     // Primitive node
02545     xmlNodePtr primNode = xmlNewDocNode (doc, NULL, (const xmlChar*)"PRIMITIVES", NULL);
02546     xmlDocSetRootElement (doc, primNode);
02547 
02548     write (primNode, filename);
02549 }
02550 
02551 // ***************************************************************************
02552 
02553 void CPrimitives::write (xmlNodePtr root, const char *filename) const
02554 {
02555     nlassert (root);
02556 
02557     // Version node
02558     xmlSetProp (root, (const xmlChar*)"VERSION", (const xmlChar*)toString (NLLIGO_PRIMITIVE_VERSION).c_str ());
02559 
02560     // The primitive root node
02561     xmlNodePtr nameNode = xmlNewChild ( root, NULL, (const xmlChar*)"ROOT_PRIMITIVE", NULL);
02562     xmlNodePtr subNode = xmlNewChild ( nameNode, NULL, (const xmlChar*)"ALIAS", NULL);
02563     WriteUInt("LAST_GENERATED", _LastGeneratedAlias, subNode);
02564 
02565     // Write the primitive tree
02566     ((IPrimitive*)RootNode)->write (nameNode, filename);
02567 }
02568 
02569 // ***************************************************************************
02570 
02571 void CPrimitives::serial(NLMISC::IStream &f)
02572 {
02573     uint currentVersion = NLLIGO_PRIMITIVE_VERSION;
02574     f.serialVersion(currentVersion);
02575 
02576     if (currentVersion == 0)
02577     {
02578         f.serial(_LastGeneratedAlias);
02579     }
02580 
02581     if (f.isReading())
02582     {
02583         RootNode->removeChildren ();
02584         RootNode->removeProperties ();
02585     }
02586     f.serialPolyPtr(RootNode);
02587     f.serial(_Filename);
02588     if (f.isReading() && _LigoConfig)
02589     {
02590         _AliasStaticPart = _LigoConfig->getFileStaticAliasMapping(_Filename);
02591     }
02592 }
02593 
02594 // ***************************************************************************
02595 
02596 void CPrimitives::convertAddPrimitive (IPrimitive *child, const IPrimitive *prim, bool hidden)
02597 {
02598     // The primitve
02599     IPrimitive *primitive = NULL;
02600 
02601     // What kind of primitive ?
02602     const CPrimPoint *oldPoint = dynamic_cast<const CPrimPoint *>(prim);
02603     if (oldPoint)
02604     {
02605         // Create a primitive
02606         CPrimPoint *point = static_cast<CPrimPoint *> (CClassRegistry::create ("CPrimPoint"));
02607         primitive = point;
02608 
02609         // Copy it
02610         *point = *oldPoint;
02611     }
02612     else
02613     {
02614         // Path ?
02615         const CPrimPath *oldPath = dynamic_cast<const CPrimPath *>(prim);
02616         if (oldPath)
02617         {
02618             // Create a primitive
02619             CPrimPath *path = static_cast<CPrimPath *> (CClassRegistry::create ("CPrimPath"));
02620             primitive = path;
02621 
02622             // Copy it
02623             *path = *oldPath;
02624         }
02625         else
02626         {
02627             const CPrimZone *oldZone = safe_cast<const CPrimZone *>(prim);
02628             if (oldZone)
02629             {
02630                 // Create a primitive
02631                 CPrimZone *zone = static_cast<CPrimZone *> (CClassRegistry::create ("CPrimZone"));
02632                 primitive = zone;
02633 
02634                 // Copy it
02635                 *zone = *oldZone;
02636             }
02637         }
02638     }
02639 
02640     // Primitive has been created ?
02641     if (primitive)
02642     {
02643         // Create a property for the name
02644         CPropertyString *nameProp = new CPropertyString;
02645 //      nameProp->String = prim->Name;
02646 
02647         // Add the property
02648         primitive->addPropertyByName ("name", nameProp);
02649 
02650         // The primitive is hidden ?
02651         if (hidden)
02652         {
02653             // Create a property for hidden
02654             nameProp = new CPropertyString;
02655 
02656             // Add the property
02657             primitive->addPropertyByName ("hidden", nameProp);
02658         }
02659 
02660         // Add the child
02661         child->insertChild (primitive);
02662     }
02663 }
02664 
02665 // ***************************************************************************
02666 
02667 void CPrimitives::convertPrimitive (const IPrimitive *prim, bool hidden)
02668 {
02669     // Look for the group
02670     uint numChildren = RootNode->getNumChildren ();
02671     uint j;
02672     for (j=0; j<numChildren; j++)
02673     {
02674         IPrimitive *child;
02675         nlverify (RootNode->getChild (child, j));
02676         const IProperty *prop;
02677         if (child->getPropertyByName ("name", prop))
02678         {
02679             // Prop string
02680             const CPropertyString *name = dynamic_cast<const CPropertyString *>(prop);
02681             if (name)
02682             {
02683                 // This one ?
02684 /*              if (name->String == prim->Layer)
02685                 {
02686                     convertAddPrimitive (child, prim, hidden);
02687                     break;
02688                 }
02689 */          }
02690         }
02691     }
02692 
02693     // Not found ?
02694     if (j==numChildren)
02695     {
02696         // Create a node
02697         CPrimNode *primNode = static_cast<CPrimNode *> (CClassRegistry::create ("CPrimNode"));
02698 
02699         // Create a property for the layer
02700         CPropertyString *nameProp = new CPropertyString;
02701 //      nameProp->String = prim->Layer;
02702 
02703         // Add the property
02704         primNode->addPropertyByName ("name", nameProp);
02705 
02706         // Add the child
02707         RootNode->insertChild (primNode);
02708 
02709         // Add the primitive
02710         convertAddPrimitive (primNode, prim, hidden);
02711     }
02712 }
02713 
02714 // ***************************************************************************
02715 
02716 void CPrimitives::convert (const CPrimRegion &region)
02717 {
02718     // Delete
02719     RootNode->removeChildren ();
02720     RootNode->removeProperties ();
02721 
02722     // For each primitives
02723     uint i;
02724     for (i=0; i<region.VPoints.size (); i++)
02725     {
02726         convertPrimitive (&(region.VPoints[i]), region.VHidePoints[i]);
02727     }
02728     for (i=0; i<region.VPaths.size (); i++)
02729     {
02730         convertPrimitive (&(region.VPaths[i]), region.VHidePaths[i]);
02731     }
02732     for (i=0; i<region.VZones.size (); i++)
02733     {
02734         convertPrimitive (&(region.VZones[i]), region.VHideZones[i]);
02735     }
02736 }
02737 
02738 // ***************************************************************************
02739 
02740 CPrimitiveContext::CPrimitiveContext():
02741     CurrentLigoConfig(NULL),
02742     CurrentPrimitive(NULL)
02743 {
02744 }
02745 
02746 
02747 void Register ()
02748 {
02749     NLMISC_REGISTER_CLASS(CPropertyString);
02750     NLMISC_REGISTER_CLASS(CPropertyStringArray);
02751     NLMISC_REGISTER_CLASS(CPropertyColor);
02752     NLMISC_REGISTER_CLASS(CPrimNode);
02753     NLMISC_REGISTER_CLASS(CPrimPoint);
02754     NLMISC_REGISTER_CLASS(CPrimPath);
02755     NLMISC_REGISTER_CLASS(CPrimZone);
02756     NLMISC_REGISTER_CLASS(CPrimAlias);
02757 }
02758 
02759 // ***************************************************************************
02760 
02761 } // namespace NLLIGO
02762 
02763 

Generated on Thu Jan 7 08:26:33 2010 for NeL by  doxygen 1.6.1