Salome HOME
Update copyright: 2016
[modules/geom.git] / src / CurveCreator / CurveCreator_Diff.cxx
1 // Copyright (C) 2013-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File:        CurveCreator_Diff.cxx
21 // Author:      Sergey KHROMOV
22
23 #include "CurveCreator_Diff.hxx"
24 #include "CurveCreator_Curve.hxx"
25
26 #include <list>
27
28 //=======================================================================
29 // function: Constructor
30 // purpose:
31 //=======================================================================
32 CurveCreator_Diff::CurveCreator_Diff()
33 : myNbUndos (0),
34   myPUndo   (NULL),
35   myPRedo   (NULL)
36 {
37 }
38
39 //=======================================================================
40 // function: Destructor
41 // purpose:
42 //=======================================================================
43 CurveCreator_Diff::~CurveCreator_Diff()
44 {
45   clear();
46 }
47
48 //=======================================================================
49 // function: init
50 // purpose:
51 //=======================================================================
52 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve)
53 {
54   CurveCreator_Operation::Type aType = CurveCreator_Operation::Clear;
55   bool isOK = false;
56
57   if (theCurve != NULL) {
58     clear();
59
60     // Set redo.
61     myPRedo = new CurveCreator_Operation;
62
63     if (myPRedo->init(aType)) {
64       isOK = true;
65
66       const int aNbSections = theCurve->getNbSections();
67
68       // Construct undo for Clear command.
69       if (aNbSections > 0) {
70         setNbUndos(aNbSections);
71
72         for (int i = 0; i < aNbSections && isOK; i++) {
73           // Add AddSection command.
74           isOK = addSectionToUndo(theCurve, i, myPUndo[i]);
75         }
76       }
77     }
78
79     if (!isOK) {
80       clear();
81     }
82   }
83
84   return isOK;
85 }
86
87 //=======================================================================
88 // function: init
89 // purpose:
90 //=======================================================================
91 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
92                              const CurveCreator_Operation::Type theType,
93                              const int theIntParam)
94 {
95   bool isOK = false;
96
97   if (theCurve != NULL) {
98     clear();
99
100     // Set redo.
101     myPRedo = new CurveCreator_Operation;
102
103     if (myPRedo->init(theType, theIntParam)) {
104       // Construct undo for RemoveSection command.
105       // If the last section is removed, one AddSection command is enough.
106       // If not last section is removed, two commands are requred: AddSection
107       // and MoveSection.
108       const int aLastIndex = theCurve->getNbSections() - 1;
109
110       if (theIntParam == aLastIndex) {
111         setNbUndos(1);
112       } else {
113         setNbUndos(2);
114       }
115
116       isOK = addSectionToUndo(theCurve, theIntParam, myPUndo[0]);
117
118       if (isOK && theIntParam != aLastIndex) {
119         isOK = myPUndo[1].init(CurveCreator_Operation::MoveSection,
120                                aLastIndex, theIntParam);
121       }
122     }
123
124     if (!isOK) {
125       clear();
126     }
127   }
128
129   return isOK;
130 }
131
132 //=======================================================================
133 // function: init
134 // purpose:
135 //=======================================================================
136 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
137                              const CurveCreator_Operation::Type theType,
138                              const int theIntParam1,
139                              const int theIntParam2)
140 {
141   bool isOK = false;
142
143   if (theCurve != NULL) {
144     clear();
145
146     // Set redo.
147     myPRedo = new CurveCreator_Operation;
148
149     if (myPRedo->init(theType, theIntParam1, theIntParam2)) {
150       // Construct undo for different commands.
151       switch (theType) {
152         case CurveCreator_Operation::SetType:
153         case CurveCreator_Operation::SetClosed:
154             isOK = setTypeOrClosedToUndo
155               (theCurve, theType, theIntParam1, theIntParam2);
156           break;
157         case CurveCreator_Operation::MoveSection:
158           setNbUndos(1);
159           isOK = myPUndo[0].init(theType, theIntParam2, theIntParam1);
160           break;
161         default:
162           break;
163       }
164     }
165
166     if (!isOK) {
167       clear();
168     }
169   }
170
171   return isOK;
172 }
173
174 //=======================================================================
175 // function: init
176 // purpose:
177 //=======================================================================
178 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
179                              const CurveCreator_Operation::Type theType,
180                              const std::list<int>& theParams)
181 {
182   bool isOK = false;
183
184   if (theCurve != NULL || theParams.empty()) {
185     clear();
186
187     // Set redo.
188     myPRedo = new CurveCreator_Operation;
189
190     if (myPRedo->init(theType, theParams)) {
191       // Construct undo for different commands.
192       switch (theType) {
193         case CurveCreator_Operation::Join:
194           {
195             int aSectionMain = theParams.front();
196             const int aNbPointsMain  = theCurve->getNbPoints(aSectionMain);
197
198             std::list<int> aSectionsToJoin = theParams;
199             aSectionsToJoin.erase( aSectionsToJoin.begin() );
200             // it is important to sort the section indices in order to correct perform undo
201             // for the move sections to the previous positions
202             aSectionsToJoin.sort();
203             // 1rst undo for remove points from the main and n-1 undoes to contain joined sections
204             int aSectionsToJoinNb = aSectionsToJoin.size();
205             int aNbUndos = 2*aSectionsToJoinNb + 1;
206             setNbUndos( aNbUndos );
207
208             // Add joined sections to undo
209             std::list<int>::const_iterator anIt = aSectionsToJoin.begin(),
210                                            aLast = aSectionsToJoin.end();
211             anIt = aSectionsToJoin.begin();
212             int aLastSectionId = -1;
213             for (int i = 0; anIt != aLast && i < aSectionsToJoinNb; anIt++, i++) {
214               int anISection = *anIt;
215               isOK = addSectionToUndo( theCurve, anISection, myPUndo[i*2] );
216               if (isOK) {
217                 isOK = myPUndo[i*2+1].init(CurveCreator_Operation::MoveSection,
218                                            aLastSectionId, anISection);
219                 if (!isOK)
220                   break;
221               }
222             }
223             // Construct undo for RemovePoints command.
224             if (isOK) {
225               int aNbPointsInJoined = 0;
226               anIt = aSectionsToJoin.begin();
227               for ( ; anIt != aLast; anIt++ )
228                 aNbPointsInJoined += theCurve->getNbPoints( *anIt );
229
230               int aJoinedSize = aNbPointsMain + aNbPointsInJoined;
231               CurveCreator_ICurve::SectionToPointList aSectionToPointList;
232               for (int anIPoint = aNbPointsMain; anIPoint < aJoinedSize; anIPoint++)
233                 aSectionToPointList.push_back(std::make_pair(aSectionMain, anIPoint));
234
235               isOK = myPUndo[aNbUndos-1].init(CurveCreator_Operation::RemovePoints, aSectionToPointList);
236             }
237           }
238           break;
239         default:
240           break;
241       }
242     }
243
244     if (!isOK) {
245       clear();
246     }
247   }
248
249   return isOK;
250 }
251
252 //=======================================================================
253 // function: init
254 // purpose:
255 //=======================================================================
256 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
257                              const CurveCreator_Operation::Type theType,
258                              const std::string& theName,
259                              const CurveCreator::Coordinates &theCoords,
260                              const int theIntParam1,
261                              const int theIntParam2)
262 {
263     bool isOK = false;
264
265     if (theCurve != NULL) {
266       clear();
267
268       // Set redo.
269       myPRedo = new CurveCreator_Operation;
270
271       if (myPRedo->init(theType, theName, theCoords, theIntParam1, theIntParam2)) {
272         // Construct undo for different commands.
273         switch (theType) {
274           case CurveCreator_Operation::AddSection:
275             setNbUndos(1);
276             isOK = myPUndo[0].init(CurveCreator_Operation::RemoveSection, -1);
277             break;
278         }
279       }
280     }
281     if( !isOK )
282         clear();
283     return isOK;
284 }
285
286 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
287                              const CurveCreator_Operation::Type theType,
288                              const std::string &theName,
289                              const int theIntParam1 )
290 {
291   bool isOK = false;
292   myPRedo = new CurveCreator_Operation;
293
294   if (myPRedo->init(theType, theName, theIntParam1 )) {
295     // Construct undo for different commands.
296     switch (theType) {
297       case CurveCreator_Operation::RenameSection:
298         setNbUndos(1);
299         isOK = myPUndo[0].init(CurveCreator_Operation::RenameSection,
300                                theCurve->getSectionName(theIntParam1), theIntParam1);
301         break;
302     }
303   }
304   if( !isOK ){
305     clear();
306   }
307   return isOK;
308 }
309
310 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
311                              const CurveCreator_Operation::Type theType,
312                              const CurveCreator_ICurve::SectionToPointList &theParamList1)
313 {
314   bool isOK = false;
315
316   if (theCurve != NULL) {
317     clear();
318
319     // Set redo.
320     myPRedo = new CurveCreator_Operation;
321
322     if (myPRedo->init(theType, theParamList1)) {
323       // Construct undo for different commands.
324       switch (theType) {
325         case CurveCreator_Operation::RemovePoints:
326           {
327             // Construct undo for RemovePoints command.
328             CurveCreator_ICurve::SectionToPointCoordsList aSectionToPointCoords;
329             CurveCreator::Coordinates aPointsToAdd;
330             const CurveCreator::Dimension aDim = theCurve->getDimension();
331             CurveCreator_ICurve::SectionToPointList::const_iterator anIt = theParamList1.begin(), aLast = theParamList1.end();
332             std::list<int> aPoints;
333             int aSectionId, aPointId;
334             for ( ; anIt != aLast; anIt++ ) {
335               aPointsToAdd.clear();
336               aSectionId = anIt->first;
337               aPointId = anIt->second;
338               const CurveCreator::Coordinates &aPoints =
339                       theCurve->getPoints(aSectionId);
340               CurveCreator::Coordinates::const_iterator anIterBegin =
341                   aPoints.begin() + (aDim*aPointId);
342               CurveCreator::Coordinates::const_iterator anIterEnd = 
343                 anIterBegin + aDim;
344               aPointsToAdd.insert(aPointsToAdd.end(), anIterBegin, anIterEnd);
345               aSectionToPointCoords.push_back(std::make_pair(*anIt, aPointsToAdd));
346             }
347             setNbUndos(1);
348             isOK = myPUndo[0].init(CurveCreator_Operation::InsertPoints,
349                                    aSectionToPointCoords);
350           }
351           break;
352         default:
353           break;
354       }
355     }
356
357     if (!isOK) {
358       clear();
359     }
360   }
361
362   return isOK;
363 }
364
365 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
366                              const CurveCreator_Operation::Type theType,
367                              const CurveCreator_ICurve::SectionToPointCoordsList &theParamList1)
368 {
369   bool isOK = false;
370
371   if (theCurve != NULL) {
372     clear();
373
374     // Set redo.
375     myPRedo = new CurveCreator_Operation;
376
377     if (myPRedo->init(theType, theParamList1)) {
378       // Construct undo for different commands.
379       switch (theType) {
380         case CurveCreator_Operation::InsertPoints:
381           {
382             // Construct undo for RemovePoints command.
383             CurveCreator_ICurve::SectionToPointList aSectionToPointList;
384             CurveCreator_ICurve::SectionToPointCoordsList::const_iterator anIt = theParamList1.begin(), aLast = theParamList1.end();
385             for ( ; anIt != aLast; anIt++ ) {
386               aSectionToPointList.push_back(anIt->first);
387             }
388             setNbUndos(1);
389             isOK = myPUndo[0].init(CurveCreator_Operation::RemovePoints,
390                                    aSectionToPointList);
391           }
392           break;
393         case CurveCreator_Operation::SetCoordinates:
394           {
395             // Construct undo for SetCoordinates command.
396             CurveCreator_ICurve::SectionToPointCoordsList aSectionToPointOldCoords;
397             CurveCreator_ICurve::SectionToPointCoordsList::const_iterator anIt = theParamList1.begin(), aLast = theParamList1.end();
398             for ( ; anIt != aLast; anIt++ ) {
399               CurveCreator::Coordinates anOldCoords = theCurve->getPoint(anIt->first.first, anIt->first.second);
400               aSectionToPointOldCoords.push_back(std::make_pair(anIt->first, anOldCoords));
401             }
402
403             setNbUndos(1);
404             isOK = myPUndo[0].init(CurveCreator_Operation::SetCoordinates,
405                                    aSectionToPointOldCoords);
406           }
407           break;
408         default:
409           break;
410       }
411     }
412
413     if (!isOK) {
414       clear();
415     }
416   }
417
418   return isOK;
419 }
420
421 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
422                              const CurveCreator_ICurve::SectionToPointCoordsList &theOldParamList)
423 {
424   bool isOK = false;
425
426   if (theCurve != NULL && theOldParamList.size() > 0) {
427     clear();
428
429     // Set redo.
430     myPRedo = new CurveCreator_Operation;
431
432     // Construct redo for SetCoordinates command.
433     CurveCreator_ICurve::SectionToPointCoordsList aSectionToPointActualCoords;
434     CurveCreator_ICurve::SectionToPointCoordsList::const_iterator anIt = 
435       theOldParamList.begin(), aLast = theOldParamList.end();
436     for ( ; anIt != aLast; anIt++ ) {
437       CurveCreator::Coordinates anActualCoords = theCurve->getPoint(anIt->first.first, anIt->first.second);
438       aSectionToPointActualCoords.push_back(std::make_pair(anIt->first, anActualCoords));
439     }
440
441     if (myPRedo->init(CurveCreator_Operation::SetCoordinates, aSectionToPointActualCoords)) {
442       // Undo for SetCoordinates command.
443       setNbUndos(1);
444       isOK = myPUndo[0].init(CurveCreator_Operation::SetCoordinates,
445                              theOldParamList);
446     }
447
448     if (!isOK) {
449       clear();
450     }
451   }
452
453   return isOK;
454 }
455
456 //=======================================================================
457 // function: applyUndo
458 // purpose:
459 //=======================================================================
460 void CurveCreator_Diff::applyUndo(CurveCreator_Curve *theCurve)
461 {
462   if (myNbUndos > 0 && myPUndo != NULL) {
463     for (int i = 0; i < myNbUndos; i++) {
464       myPUndo[i].apply(theCurve);
465     }
466   }
467 }
468
469 //=======================================================================
470 // function: applyRedo
471 // purpose:
472 //=======================================================================
473 void CurveCreator_Diff::applyRedo(CurveCreator_Curve *theCurve)
474 {
475   if (myPRedo != NULL) {
476     myPRedo->apply(theCurve);
477   }
478 }
479
480 //=======================================================================
481 // function: clear
482 // purpose:
483 //=======================================================================
484 void CurveCreator_Diff::clear()
485 {
486   if (myPUndo != NULL) {
487     delete [] myPUndo;
488     myPUndo = NULL;
489   }
490
491   myNbUndos = 0;
492
493   if (myPRedo != NULL) {
494     delete myPRedo;
495     myPRedo = NULL;
496   }
497 }
498
499 //=======================================================================
500 // function: setNbUndos
501 // purpose:
502 //=======================================================================
503 void CurveCreator_Diff::setNbUndos(const int theNbUndos)
504 {
505   myNbUndos = theNbUndos;
506   myPUndo = new CurveCreator_Operation[myNbUndos];
507 }
508
509 //=======================================================================
510 // function: getSectionIndex
511 // purpose:
512 //=======================================================================
513 int CurveCreator_Diff::getSectionIndex(const CurveCreator_Curve *theCurve,
514                                        const int theIndex) const
515 {
516   return (theIndex == -1 ? theCurve->getNbSections() - 1 : theIndex);
517 }
518
519 //=======================================================================
520 // function: addSectionToUndo
521 // purpose:
522 //=======================================================================
523 bool CurveCreator_Diff::addSectionToUndo
524                       (const CurveCreator_Curve *theCurve,
525                        const int theIndex,
526                        CurveCreator_Operation &theOperation) const
527 {
528   const std::string aName = theCurve->getSectionName(theIndex);
529   const CurveCreator::Coordinates &aPnts = theCurve->getPoints(theIndex);
530   const CurveCreator::SectionType aType = theCurve->getSectionType(theIndex);
531   const bool isClosed = theCurve->isClosed(theIndex);
532
533   bool isOK = theOperation.init(CurveCreator_Operation::AddSection,
534                                 aName, aPnts, aType, isClosed);
535
536   return isOK;
537 }
538
539 //=======================================================================
540 // function: setTypeOrClosedToUndo
541 // purpose:
542 //=======================================================================
543 bool CurveCreator_Diff::setTypeOrClosedToUndo
544                             (const CurveCreator_Curve *theCurve,
545                              const CurveCreator_Operation::Type theType,
546                              const int theIntParam1,
547                              const int theIntParam2)
548 {
549   bool isOK = true;
550
551   // Compute number of modified sections.
552   const bool isSetType = (theType == CurveCreator_Operation::SetType);
553   int aNbModif = 0;
554   std::list<int> aListOfInd;
555   int aValue;
556   int i;
557
558   if (theIntParam2 == -1) {
559     // The operation is applied to all sections. We need to collect
560     // really modified sections for undo.
561     const int aNbSections = theCurve->getNbSections();
562
563     if (aNbSections > 0) {
564       // Get sections to be modified.
565       for (i = 0; i < aNbSections; i++) {
566         if (isSetType) {
567           aValue = theCurve->getSectionType(i);
568         } else {
569           aValue = theCurve->isClosed(i);
570         }
571
572         if (theIntParam1 != aValue) {
573           aNbModif++;
574           aListOfInd.push_back(i);
575         }
576       }
577
578       if (aNbSections == aNbModif) {
579         // All sections are modified. We can use one single command
580         // with -1 section index.
581         aNbModif = 1;
582         aListOfInd.clear();
583         aListOfInd.push_back(-1);
584       }
585     }
586   } else {
587     // There is only particular section modified.
588     // Check if there is a real modification required.
589     if (isSetType) {
590       aValue = theCurve->getSectionType(theIntParam2);
591     } else {
592       aValue = theCurve->isClosed(theIntParam2);
593     }
594
595     if (theIntParam1 != aValue) {
596       aNbModif = 1;
597       aListOfInd.push_back(theIntParam2);
598     }
599   }
600
601   if (aNbModif > 0) {
602     // Store the undos
603     std::list<int>::iterator anIter = aListOfInd.begin();
604
605     if (isSetType) {
606       aValue = theCurve->getSectionType(*anIter);
607     } else {
608       aValue = theCurve->isClosed(*anIter);
609     }
610
611     setNbUndos(aNbModif);
612
613     for (i = 0; anIter != aListOfInd.end() && isOK; i++, anIter++) {
614       isOK = myPUndo[i].init(theType, aValue, *anIter);
615     }
616   }
617
618   return isOK;
619 }