]> SALOME platform Git repositories - modules/hydro.git/blob - src/HYDROData/HYDROData_Document.cxx
Salome HOME
refs #369: support of local CS
[modules/hydro.git] / src / HYDROData / HYDROData_Document.cxx
1
2 #include <HYDROData_Document.h>
3 #include <HYDROData_Application.h>
4 #include <HYDROData_Iterator.h>
5 #include <HYDROData_Tool.h>
6
7 #include <TDataStd_Integer.hxx>
8 #include <TDataXtd_Position.hxx>
9
10 #include <TDF_Delta.hxx>
11
12 #include <gp_Pnt2d.hxx>
13 #include <gp_Pnt.hxx>
14
15 #include <QFile>
16 #include <QStringList>
17 #include <QTextStream>
18
19 IMPLEMENT_STANDARD_HANDLE(HYDROData_Document,MMgt_TShared)
20 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Document,MMgt_TShared)
21
22 #define PYTHON_DOC_NAME "hydro_doc"
23
24 static const int UNDO_LIMIT = 10; // number of possible undo operations in the module
25
26 static const int TAG_PROPS = 1; // general properties tag
27 static const int TAG_PROPS_NEW_ID = 1; // general properties: tag for storage of the new object ID
28 static const int TAG_OBJECTS = 2; // tag of the objects sub-tree
29 static const int TAG_HISTORY = 3; // tag of the history sub-tree (Root for History)
30 static const int TAG_LOCAL_CS = 4; // tag of local coordinate system information
31 static const gp_Pnt2d DEFAULT_LOCAL_CS( 0, 0 );
32
33 using namespace std;
34
35 typedef QMap<Standard_Integer,Handle_HYDROData_Entity> MapOfOrdered;
36 typedef QMap<QString,Handle_HYDROData_Entity> MapOfUnordered;
37
38 Handle(HYDROData_Document) HYDROData_Document::Document(const int theStudyID)
39 {
40   Handle(HYDROData_Document) aResult = 
41     HYDROData_Application::GetApplication()->GetDocument(theStudyID);
42   if (aResult.IsNull()) {
43     aResult = new HYDROData_Document();
44     HYDROData_Application::GetApplication()->AddDocument(theStudyID, aResult);
45   }
46   return aResult;
47 }
48
49 Handle(HYDROData_Document) HYDROData_Document::Document(
50   const TDF_Label& theObjectLabel )
51 {
52   Handle(HYDROData_Document) aResDoc;
53   if ( theObjectLabel.IsNull() )
54     return aResDoc;
55
56   Handle(TDocStd_Document) anObjDoc;
57   try
58   {
59     anObjDoc = TDocStd_Document::Get( theObjectLabel );
60   }
61   catch( ... )
62   {
63   }
64
65   if ( anObjDoc.IsNull() )
66     return aResDoc;
67
68   HYDROData_Application* anApp = HYDROData_Application::GetApplication();
69
70   DataMapOfStudyIDDocument::Iterator aMapIt( anApp->myDocuments );
71   for ( ; aMapIt.More(); aMapIt.Next() )
72   {
73     Handle(HYDROData_Document) anAppDoc = aMapIt.Value();
74     if ( anAppDoc.IsNull() || anAppDoc->myDoc != anObjDoc )
75       continue;
76
77     aResDoc = anAppDoc;
78     break;
79   }
80
81   return aResDoc;
82 }
83
84 bool HYDROData_Document::HasDocument(const int theStudyID)
85 {
86   Handle(HYDROData_Document) aResult = 
87     HYDROData_Application::GetApplication()->GetDocument(theStudyID);
88   return !aResult.IsNull();
89 }
90
91 bool HYDROData_Document::DocumentId(const Handle(HYDROData_Document)& theDocument,
92                                     int&                              theDocId )
93 {
94   return HYDROData_Application::GetApplication()->GetDocumentId(theDocument, theDocId);
95 }
96
97 Data_DocError HYDROData_Document::Load(const char* theFileName, const int theStudyID)
98 {
99   Handle(TDocStd_Document) aResult;
100   TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
101   PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
102   try
103   {
104     aStatus = HYDROData_Application::GetApplication()->Open (aPath, aResult);
105   }
106   catch (Standard_Failure)
107   {}
108   if (!aResult.IsNull()) {
109     aResult->SetUndoLimit(UNDO_LIMIT);
110     HYDROData_Application::GetApplication()->AddDocument(theStudyID, new HYDROData_Document(aResult));
111   }
112   // recognize error
113   Data_DocError anError;
114   switch(aStatus) {
115   case PCDM_RS_OK:
116     anError = DocError_OK;
117     break;
118   case PCDM_RS_NoDriver:
119   case PCDM_RS_UnknownFileDriver:
120   case PCDM_RS_NoSchema:
121   case PCDM_RS_DriverFailure:
122   case PCDM_RS_WrongResource:
123     anError = DocError_ResourcesProblem;
124     break;
125   case PCDM_RS_OpenError:
126   case PCDM_RS_NoDocument:
127   case PCDM_RS_WrongStreamMode:
128   case PCDM_RS_PermissionDenied:
129     anError = DocError_CanNotOpen;
130     break;
131   case PCDM_RS_NoVersion:
132     anError = DocError_InvalidVersion;
133     break;
134   case PCDM_RS_ExtensionFailure:
135   case PCDM_RS_FormatFailure:
136   case PCDM_RS_TypeFailure:
137   case PCDM_RS_TypeNotFoundInSchema:
138   case PCDM_RS_UnrecognizedFileFormat:
139     anError = DocError_InvalidFormat;
140     break;
141   case PCDM_RS_MakeFailure:
142   default:
143     anError = DocError_UnknownProblem;
144     break;
145   }
146   return anError;
147 }
148
149 Data_DocError HYDROData_Document::Save(const char* theFileName)
150 {
151   TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
152   PCDM_StoreStatus aStatus;
153   try {
154     aStatus = HYDROData_Application::GetApplication()->SaveAs (myDoc, aPath);
155   }
156   catch (Standard_Failure) {}
157   myTransactionsAfterSave = 0;
158   Standard::Purge(); // Release free memory
159
160   // recognize error
161   Data_DocError anError;
162   switch(aStatus) {
163   case PCDM_SS_OK:
164     anError = DocError_OK;
165     break;
166   case PCDM_SS_DriverFailure:
167     anError = DocError_ResourcesProblem;
168     break;
169   case PCDM_SS_WriteFailure:
170   //case PCDM_SS_DiskWritingFailure:
171   //case PCDM_SS_UserRightsFailure:
172     anError = DocError_CanNotOpen;
173     break;
174   default:
175     anError = DocError_UnknownProblem;
176     break;
177   }
178   return anError;
179 }
180
181 void HYDROData_Document::Close()
182 {
183   myDoc->Close();
184   HYDROData_Application::GetApplication()->RemoveDocument(this);
185 }
186
187 bool HYDROData_Document::DumpToPython( const QString& theFileName,
188                                        const bool     theIsMultiFile ) const
189 {
190   // Try to open the file
191   QFile aFile( theFileName );
192   if ( !aFile.open( QIODevice::WriteOnly ) )
193     return false;
194
195   MapOfTreatedObjects aTreatedObjects;
196
197   // Dump header for python script
198   QStringList aHeaderDump = DumpToPython( aTreatedObjects, theIsMultiFile );
199   if ( aHeaderDump.isEmpty() )
200     return false;
201
202   HYDROData_Tool::WriteStringsToFile( aFile, aHeaderDump );
203
204   bool aRes = true;
205
206   // Dump all model objects to Python script
207   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_IMAGE );
208   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_POLYLINEXY );
209   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_BATHYMETRY );
210   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_PROFILE );
211   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_POLYLINE );
212   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_IMMERSIBLE_ZONE );
213   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_STREAM );
214   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_CHANNEL );
215   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_DIGUE );
216   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_OBSTACLE );
217   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_CALCULATION );
218
219   // Dump code to close python fuction
220   if ( aRes && theIsMultiFile )
221   {
222     QStringList aFooterScript;
223     aFooterScript << QString( "" );
224     aFooterScript << QString( "  pass" );
225     HYDROData_Tool::WriteStringsToFile( aFile, aFooterScript );
226   }
227
228   return aRes;
229 }
230
231 QString HYDROData_Document::GetDocPyName() const
232 {
233   QString aDocName = PYTHON_DOC_NAME;
234   
235   /*
236   int aDocId = 1;
237   if ( DocumentId( this, aDocId ) )
238     aDocName += "_" + QString::number( aDocId );
239   */
240   
241   return aDocName;
242 }
243
244 QStringList HYDROData_Document::DumpToPython( MapOfTreatedObjects& theTreatedObjects,
245                                               const bool           theIsMultiFile ) const
246 {
247   QString aDocName = GetDocPyName();
248
249   // Append document in to the map of treated objects to prevent names overlaping
250   theTreatedObjects.insert( aDocName, this );
251
252   int aDocId = 1;
253   if ( !DocumentId( this, aDocId ) )
254     aDocId = 1;
255
256   QStringList aResScript;
257
258   aResScript << QString( "from HYDROPy import *" );
259   aResScript << QString( "from PyQt4.QtCore import *" );
260   aResScript << QString( "from PyQt4.QtGui import *" );
261
262   if ( theIsMultiFile )
263   {
264     aResScript << QString( "" );
265     aResScript << QString( "def RebuildData( theStudy ):" );
266     aResScript << QString( "  %1 = HYDROData_Document.Document( theStudy._get_StudyId() );" ).arg( aDocName );
267   }
268   else
269   {
270     aResScript << QString( "" );
271     aResScript << QString( "%1 = HYDROData_Document.Document( theStudy._get_StudyId() );" ).arg( aDocName );
272   }
273
274   return aResScript;
275 }
276
277 bool HYDROData_Document::dumpPartitionToPython( QFile&               theFile,
278                                                 const bool           theIsMultiFile,
279                                                 MapOfTreatedObjects& theTreatedObjects,
280                                                 const ObjectKind&    theObjectKind ) const
281 {
282   if ( !theFile.isOpen() )
283     return false;
284
285   QTextStream anOutStream( &theFile );
286
287   bool aRes = true;
288
289   HYDROData_Iterator anIterator( this, theObjectKind );
290   for( ; anIterator.More(); anIterator.Next() )
291   {
292     Handle(HYDROData_Entity) anObject = anIterator.Current();
293     if ( anObject.IsNull() )
294       continue;
295
296     QString anObjName = anObject->GetName();
297     if ( theTreatedObjects.contains( anObjName ) )
298       continue;
299
300     theTreatedObjects.insert( anObjName, anObject );
301
302     QStringList anObjDump = anObject->DumpToPython( theTreatedObjects );
303
304     if ( theIsMultiFile )
305     {
306       // For multifile dump we use the function, see the document dump header
307       QStringList::iterator anIt = anObjDump.begin();
308       for ( ; anIt != anObjDump.end(); ++anIt )
309         anIt->prepend( "  " );
310     }
311     
312     HYDROData_Tool::WriteStringsToFile( theFile, anObjDump );
313   }
314   
315   return aRes;
316 }
317
318 bool takeLastDigits( QString& theStr, int& aRes )
319 {
320   aRes = -1;
321
322   QString anStrNum;
323   for ( int i = theStr.length() - 1; i >= 0; --i )
324   {
325     const QChar& aChar = theStr.at( i );
326     if ( !aChar.isDigit() )
327       break;
328
329     anStrNum.prepend( aChar );
330   }
331
332   if ( anStrNum.isEmpty() )
333     return false;
334
335   theStr.remove( theStr.length() - anStrNum.length(), anStrNum.length() );
336   aRes = anStrNum.toInt();
337
338   return true;
339 }
340
341 bool isObjectNameLessThan( const QString& theStr1, const QString& theStr2 )
342 {
343   QString aStr1 = theStr1, aStr2 = theStr2;
344
345   int aNum1 = -1, aNum2 = -1;
346   if ( takeLastDigits( aStr1, aNum1 ) && takeLastDigits( aStr2, aNum2 ) )
347   {
348     if ( aStr1 == aStr2 )
349       return aNum1 < aNum2;
350   }
351
352   return theStr1 < theStr2;
353 }
354
355 HYDROData_SequenceOfObjects HYDROData_Document::GetObjectsLayerOrder(
356   const Standard_Boolean theIsAll ) const
357 {
358   HYDROData_SequenceOfObjects anOrder;
359
360   MapOfOrdered   aMapOfOrdered;
361   MapOfUnordered aMapOfUnordered;
362
363   HYDROData_Iterator anIter( this );
364   for ( ; anIter.More(); anIter.Next() )
365   {
366     Handle(HYDROData_Entity) anObject = anIter.Current();
367     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
368       continue;
369
370     Standard_Integer anObjZLevel = -1;
371     if ( anObject->GetZLevel( anObjZLevel ) )
372     {
373       aMapOfOrdered.insert( anObjZLevel, anObject );
374     }
375     else
376     {
377       QString anObjName = anObject->GetName();
378       if ( anObjName.isEmpty() )
379         continue;
380
381       aMapOfUnordered.insert( anObjName, anObject );
382     }
383   }
384
385   MapOfOrdered::const_iterator anOrderedMapIt = aMapOfOrdered.constBegin();
386   for ( ; anOrderedMapIt != aMapOfOrdered.constEnd(); anOrderedMapIt++ )
387   {
388     const Handle(HYDROData_Entity)& anObject = anOrderedMapIt.value();
389     anOrder.Prepend( anObject );
390   }
391
392   if ( theIsAll )
393   {
394     QStringList aSortedNames = aMapOfUnordered.keys();
395     qSort( aSortedNames.begin(), aSortedNames.end(), isObjectNameLessThan );
396
397     for ( int i = 0; i < aSortedNames.length(); ++i )
398     {
399       QString anObjName = aSortedNames.value( i );
400
401       const Handle(HYDROData_Entity)& anObject = aMapOfUnordered.value( anObjName );
402       anOrder.Append( anObject );
403     }
404   }
405
406   return anOrder;
407 }
408
409 void HYDROData_Document::SetObjectsLayerOrder( const HYDROData_SequenceOfObjects& theOrder )
410 {
411   // At first we remove previous model order
412   RemoveObjectsLayerOrder();
413
414   // Make new objects order
415   Standard_Integer aLevel = 0;
416   for ( int i = theOrder.Length(), n = 1; i >= n; --i )
417   {
418     const Handle(HYDROData_Entity)& anObject = theOrder.Value( i );
419     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
420       continue;
421
422     anObject->SetZLevel( aLevel++ );
423   }
424 }
425
426 void HYDROData_Document::Show( const Handle_HYDROData_Entity& theObject )
427 {
428   HYDROData_SequenceOfObjects anOrder;
429   anOrder.Append( theObject );
430   Show( anOrder );
431 }
432
433 void HYDROData_Document::Show( const HYDROData_SequenceOfObjects& theObjects )
434 {
435   MapOfUnordered aMapOfUnordered;
436
437   for ( int i = 1, n = theObjects.Length(); i <= n; ++i )
438   {
439     const Handle(HYDROData_Entity)& anObject = theObjects.Value( i );
440     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
441       continue;
442
443     Standard_Integer anObjZLevel = -1;
444     if ( anObject->GetZLevel( anObjZLevel ) )
445     {
446       continue; // Skip objects that already have the z-level
447     }
448     else
449     {
450       QString anObjName = anObject->GetName();
451       if ( anObjName.isEmpty() )
452         continue;
453
454       aMapOfUnordered.insert( anObjName, anObject );
455     }
456   }
457
458   if ( aMapOfUnordered.isEmpty() )
459     return; // Nothing to show
460
461   Standard_Integer aTopId = 0;
462
463   HYDROData_SequenceOfObjects aModelOrder = GetObjectsLayerOrder( Standard_False );
464   if ( !aModelOrder.IsEmpty() )
465   {
466     const Handle(HYDROData_Entity)& anObject = aModelOrder.First();
467     anObject->GetZLevel( aTopId );
468     aTopId++;
469   }
470
471   aTopId += aMapOfUnordered.size() - 1;
472
473   QStringList aSortedNames = aMapOfUnordered.keys();
474   qSort( aSortedNames.begin(), aSortedNames.end(), isObjectNameLessThan );
475
476   for ( int i = 0; i < aSortedNames.length(); ++i )
477   {
478     QString anObjName = aSortedNames.value( i );
479
480     const Handle(HYDROData_Entity)& anObject = aMapOfUnordered.value( anObjName );
481     anObject->SetZLevel( aTopId-- );
482   }
483 }
484
485 void HYDROData_Document::RemoveObjectsLayerOrder()
486 {
487   HYDROData_Iterator anIter( this );
488   for ( ; anIter.More(); anIter.Next() )
489   {
490     Handle(HYDROData_Entity) anObject = anIter.Current();
491     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
492       continue;
493
494     anObject->RemoveZLevel();
495   }
496 }
497
498 void HYDROData_Document::StartOperation()
499 {
500   myDoc->NewCommand();
501 }
502
503 void HYDROData_Document::CommitOperation(const TCollection_ExtendedString& theName)
504 {
505   if( !myDoc->CommitCommand() ) // it means that there were no modifications done
506   {
507     myDoc->NewCommand();
508     NewID(); // workaround: do something just to modify the document
509     myDoc->CommitCommand();
510   }
511   myTransactionsAfterSave++;
512
513   if( theName.Length() != 0 )
514   {
515     const TDF_DeltaList& aList = GetUndos();
516     if( !aList.IsEmpty() )
517     {
518       Handle(TDF_Delta) aDelta = aList.Last();
519       if( !aDelta.IsNull() )
520         aDelta->SetName( theName );
521     }
522   }
523 }
524
525 void HYDROData_Document::AbortOperation()
526 {
527   myDoc->AbortCommand();
528 }
529
530 bool HYDROData_Document::IsOperation()
531 {
532   return myDoc->HasOpenCommand() != 0;
533 }
534
535 bool HYDROData_Document::IsModified()
536 {
537   return myTransactionsAfterSave != 0;
538 }
539
540 bool HYDROData_Document::CanUndo()
541 {
542   return myDoc->GetAvailableUndos() > 0;
543 }
544
545 const TDF_DeltaList& HYDROData_Document::GetUndos()
546 {
547   return myDoc->GetUndos();
548 }
549
550 void HYDROData_Document::ClearUndos()
551 {
552   return myDoc->ClearUndos();
553 }
554
555 void HYDROData_Document::Undo()
556 {
557   myDoc->Undo();
558   myTransactionsAfterSave--;
559 }
560
561 bool HYDROData_Document::CanRedo()
562 {
563   return myDoc->GetAvailableRedos() > 0;
564 }
565
566 const TDF_DeltaList& HYDROData_Document::GetRedos()
567 {
568   return myDoc->GetRedos();
569 }
570
571 void HYDROData_Document::ClearRedos()
572 {
573   return myDoc->ClearRedos();
574 }
575
576 void HYDROData_Document::Redo()
577 {
578   myDoc->Redo();
579   myTransactionsAfterSave++;
580 }
581
582 Handle(HYDROData_Entity) HYDROData_Document::CreateObject( const ObjectKind theKind )
583 {
584   return HYDROData_Iterator::CreateObject( this, theKind );
585 }
586
587 Handle(HYDROData_Entity) HYDROData_Document::FindObjectByName( 
588   const QString&   theName,
589   const ObjectKind theObjectKind ) const
590 {
591   Handle(HYDROData_Entity) anObject;
592   if ( theName.isEmpty() )
593     return anObject;
594
595   QStringList aNamesList;
596   aNamesList << theName;
597
598   HYDROData_SequenceOfObjects aSeqOfObjs = FindObjectsByNames( aNamesList, theObjectKind );
599   if( aSeqOfObjs.IsEmpty() )
600     return anObject;
601   
602   anObject = aSeqOfObjs.First();
603   return anObject;
604 }
605
606 HYDROData_SequenceOfObjects HYDROData_Document::FindObjectsByNames(
607   const QStringList& theNames, 
608   const ObjectKind   theObjectKind ) const
609 {
610   HYDROData_SequenceOfObjects aResSeq;
611
612   QStringList aNamesList = theNames;
613
614   HYDROData_Iterator anIter( this, theObjectKind );
615   for( ; anIter.More(); anIter.Next() )
616   {
617     Handle(HYDROData_Entity) anObject = anIter.Current();
618     if( anObject.IsNull() )
619       continue;
620
621     QString anObjName = anObject->GetName();
622     if ( anObjName.isEmpty() || !aNamesList.contains( anObjName ) )
623       continue;
624
625     aResSeq.Append( anObject );
626
627     aNamesList.removeAll( anObjName );
628     if ( aNamesList.isEmpty() )
629       break;
630   }
631
632   return aResSeq;
633 }
634
635 HYDROData_Document::HYDROData_Document()
636 {
637   HYDROData_Application::GetApplication()->NewDocument("BinOcaf", myDoc);
638   myDoc->SetUndoLimit(UNDO_LIMIT);
639   NewID(); // needed to have at least one attribute in initial document to avoid errors
640   myTransactionsAfterSave = 0;
641 }
642
643 HYDROData_Document::HYDROData_Document(const Handle(TDocStd_Document)& theDoc)
644 {
645   myDoc = theDoc;
646   myTransactionsAfterSave = 0;
647 }
648
649 HYDROData_Document::~HYDROData_Document()
650 {
651 }
652
653 int HYDROData_Document::NewID()
654 {
655   TDF_Label anIDLab = myDoc->Main().FindChild(TAG_PROPS).
656     FindChild(TAG_PROPS_NEW_ID);
657   Handle(TDataStd_Integer) anInt;
658   if (!anIDLab.FindAttribute(TDataStd_Integer::GetID(), anInt)) {
659     anInt = TDataStd_Integer::Set(anIDLab, 0);
660   }
661   // just increment value and return
662   anInt->Set(anInt->Get() + 1);
663   return anInt->Get();
664 }
665
666 TDF_Label HYDROData_Document::LabelOfObjects()
667 {
668   return myDoc->Main().FindChild(TAG_OBJECTS);
669 }
670
671 TDF_Label HYDROData_Document::LabelOfLocalCS() const
672 {
673   return myDoc->Main().FindChild(TAG_LOCAL_CS);
674 }
675
676 gp_Pnt2d HYDROData_Document::GetLocalCS() const
677 {
678   TDF_Label aLocalCSLab = LabelOfLocalCS();
679
680   Handle( TDataXtd_Position ) aLocalCS;
681   if( aLocalCSLab.FindAttribute( TDataXtd_Position::GetID(), aLocalCS ) )
682   {
683     gp_Pnt aLocalCS3d = aLocalCS->GetPosition();
684     return gp_Pnt2d( aLocalCS3d.X(), aLocalCS3d.Y() );
685   }
686   else
687     return DEFAULT_LOCAL_CS;
688 }
689
690 void HYDROData_Document::SetLocalCS( const gp_Pnt2d& theLocalCS )
691 {
692   TDF_Label aLocalCSLab = LabelOfLocalCS();
693
694   Handle( TDataXtd_Position ) aLocalCS;
695   if( !aLocalCSLab.FindAttribute( TDataXtd_Position::GetID(), aLocalCS ) )
696     aLocalCS = TDataXtd_Position::Set( aLocalCSLab );
697
698   gp_Pnt aLocalCS3d( theLocalCS.X(), theLocalCS.Y(), 0 );
699   aLocalCS->SetPosition( aLocalCS3d );
700 }