2b78a4b76b1038b24ffc246dccd4a41e086c033e
[occt.git] / src / IGESData / IGESData_IGESWriter.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14
15 #include <gp_XY.hxx>
16 #include <gp_XYZ.hxx>
17 #include <IGESData_ColorEntity.hxx>
18 #include <IGESData_DefType.hxx>
19 #include <IGESData_DirPart.hxx>
20 #include <IGESData_GlobalSection.hxx>
21 #include <IGESData_IGESEntity.hxx>
22 #include <IGESData_IGESModel.hxx>
23 #include <IGESData_IGESWriter.hxx>
24 #include <IGESData_LabelDisplayEntity.hxx>
25 #include <IGESData_LevelListEntity.hxx>
26 #include <IGESData_LineFontEntity.hxx>
27 #include <IGESData_Protocol.hxx>
28 #include <IGESData_ReadWriteModule.hxx>
29 #include <IGESData_TransfEntity.hxx>
30 #include <IGESData_UndefinedEntity.hxx>
31 #include <IGESData_ViewKindEntity.hxx>
32 #include <IGESData_WriterLib.hxx>
33 #include <Interface_EntityIterator.hxx>
34 #include <Interface_FileParameter.hxx>
35 #include <Interface_FloatWriter.hxx>
36 #include <Interface_InterfaceError.hxx>
37 #include <Interface_InterfaceMismatch.hxx>
38 #include <Interface_Macros.hxx>
39 #include <Interface_ParamList.hxx>
40 #include <Interface_ParamSet.hxx>
41 #include <Interface_ReportEntity.hxx>
42 #include <Message.hxx>
43 #include <Message_Messenger.hxx>
44 #include <Standard_PCharacter.hxx>
45 #include <TCollection_AsciiString.hxx>
46 #include <TCollection_HAsciiString.hxx>
47
48 #include <stdio.h>
49 #define MaxcarsG 72
50 #define MaxcarsP 64
51
52 //#define PATIENCELOG
53
54
55 // Constructeur complet : taille OK, et se remplit depuis le modele en direct
56
57 IGESData_IGESWriter::IGESData_IGESWriter
58   (const Handle(IGESData_IGESModel)& amodel)
59     : thedirs(0,amodel->NbEntities()) , thepnum(1,amodel->NbEntities()+1),
60       thecurr (MaxcarsG+1) , themodew (0) , thefloatw (9) 
61 {
62   themodel = amodel;
63   thehead  = new TColStd_HSequenceOfHAsciiString();
64   thesep   = ',';
65   theendm  = ';';
66   thepars  = new TColStd_HSequenceOfHAsciiString();
67   thepnum.SetValue(1,1);     // debut des parametres de la 1re entite
68   thesect  = 0;
69   thepnum.Init(0);
70 //  Format flottant : cf FloatWriter
71 }
72
73     IGESData_IGESWriter::IGESData_IGESWriter ()
74     : thedirs (0,0) , thepnum (1,1) , thecurr (MaxcarsG+1) , thefloatw (9)      {  }
75
76     IGESData_IGESWriter::IGESData_IGESWriter (const IGESData_IGESWriter& )
77     : thedirs (0,0) , thepnum (1,1) , thecurr (MaxcarsG+1) , thefloatw (9)    {  }
78
79
80 //  ....                Controle d Envoi des Flottants                ....
81
82     Interface_FloatWriter& IGESData_IGESWriter::FloatWriter ()
83       {  return thefloatw;  }    // s y reporter
84
85     Standard_Integer&  IGESData_IGESWriter::WriteMode ()
86       {  return themodew;  }
87
88 //  #####################################################################
89 //  ########                GENERATION DU FICHIER                ########
90
91 //=======================================================================
92 //function : SendStartLine
93 //purpose  : 
94 //=======================================================================
95 void IGESData_IGESWriter::SendStartLine (const Standard_CString startline)
96 {
97   Standard_PCharacter pstartline;
98   //
99   pstartline=(Standard_PCharacter)startline;
100   //
101   Standard_Size lst = strlen (startline);
102   if (lst == 0) return;
103   if (thestar.IsNull()) thestar = new TColStd_HSequenceOfHAsciiString();
104   if (lst <= (Standard_Size)MaxcarsG) {
105     thestar->Append (new TCollection_HAsciiString(startline));
106     return;
107   }
108 //  Trop longue : on passe par bouts
109   char startchar = startline[MaxcarsG];
110   pstartline[MaxcarsG] = '\0';
111   SendStartLine(startline);
112   pstartline[MaxcarsG] = startchar;
113   SendStartLine (&startline[MaxcarsG]);
114 }
115
116     void IGESData_IGESWriter::SendModel
117   (const Handle(IGESData_Protocol)& protocol)
118 {
119   Handle(Message_Messenger) sout = Message::DefaultMessenger();
120   IGESData_WriterLib lib(protocol);
121
122   Standard_Integer nb = themodel->NbEntities();
123 #ifdef PATIENCELOG
124   sout<< " IGESWriter : " << nb << " Entities (* = 1000 Ent.s)" << endl;
125 #endif
126   SectionS   ();
127   Standard_Integer ns = themodel->NbStartLines();
128   Standard_Integer i; // svv Jan11 2000 : porting on DEC
129   for (i = 1; i <= ns; i ++) SendStartLine (themodel->StartLine(i));
130   SectionG   (themodel->GlobalSection());
131   SectionsDP ();
132   for (i = 1; i <= nb; i ++) {
133     Handle(IGESData_IGESEntity) ent = themodel->Entity(i);
134     Handle(IGESData_IGESEntity) cnt = ent;
135 #ifdef PATIENCELOG
136     if (i % 1000 == 1) cout << "*" << flush;
137 #endif
138 //  Attention aux cas d erreur : contenu redefini
139     if (themodel->IsRedefinedContent(i)) {
140       sout << " --  IGESWriter : Erroneous Entity N0."<<i<<"  --"<<endl;
141       Handle(Interface_ReportEntity) rep = themodel->ReportEntity(i);
142       if (!rep.IsNull()) cnt = GetCasted(IGESData_IGESEntity,rep->Content());
143       if (cnt.IsNull())  cnt = ent;    // secours
144     }
145
146     DirPart         (cnt);
147     OwnParams       (ent);  // preparation : porte sur le vrai <ent> ...
148
149 //  Envoi proprement dit des Parametres proprement definis
150     Handle(IGESData_ReadWriteModule) module;  Standard_Integer CN;
151 //  Differents cas
152     if (lib.Select(cnt,module,CN))
153       module->WriteOwnParams (CN,cnt,*this);
154     else if (cnt->IsKind(STANDARD_TYPE(IGESData_UndefinedEntity))) {
155       DeclareAndCast(IGESData_UndefinedEntity,undent,cnt);
156       undent->WriteOwnParams (*this);
157     }
158     else sout<<" -- IGESWriter : Not Processed for n0."<<i<<" in file,  Type "
159       <<cnt->TypeNumber()<<"  Form "<<cnt->FormNumber()<<endl;
160
161     Associativities (cnt);
162     Properties      (cnt);
163     EndEntity ();
164   }
165 #ifdef PATIENCELOG
166   cout << " Envoi des Entites Termine"<<endl;
167 #endif
168   SectionT();
169 }
170
171
172     void IGESData_IGESWriter::SectionS ()
173 {
174   if (thesect != 0) throw Interface_InterfaceError("IGESWriter : SectionS");
175   thesect = 1;
176 }
177
178     void IGESData_IGESWriter::SectionG (const IGESData_GlobalSection& header)
179 {
180   if (thesect != 1) throw Interface_InterfaceError("IGESWriter : SectionG");
181   thesect = 2;
182   thesep  = header.Separator();
183   theendm = header.EndMark();
184   thecurr.SetMax (MaxcarsG);
185   //   Important : les Parametres sont sortis sous leur forme definitive
186   //   (c-a-d Hollerith pour les Textes ...)
187   Handle(Interface_ParamSet) gl = header.Params();
188   Standard_Integer nb = gl->NbParams();
189   for (Standard_Integer i = 1; i <= nb; i ++) {
190     const Interface_FileParameter& FP = gl->Param(i);
191     AddString(FP.CValue());
192     if (i < nb) AddChar(thesep);
193     else        AddChar(theendm);
194   }
195   if (thecurr.Length() > 0) thehead->Append(thecurr.Moved());
196 }
197
198     void IGESData_IGESWriter::SectionsDP ()
199 {
200   if (thesect != 2) throw Interface_InterfaceError("IGESWriter : SectionsDP");
201   thesect = 3;
202   thecurr.SetMax (MaxcarsP);
203   thestep = IGESData_ReadEnd;
204 }
205
206     void IGESData_IGESWriter::SectionT ()
207 {
208   if (thesect != 3) throw Interface_InterfaceError("IGESWriter : SectionT");
209   thesect = 4;
210   thepnum.SetValue(thepnum.Length(),thepars->Length()+1);
211 }
212
213
214     void IGESData_IGESWriter::DirPart
215       (const Handle(IGESData_IGESEntity)& anent)
216 {
217   if (thesect != 3 && thestep != IGESData_ReadEnd)
218     throw Interface_InterfaceError("IGESWriter : DirPart");
219   Standard_Integer v[17]; Standard_Character res1[9],res2[9],label[9],snum[9];
220   Standard_Integer nument = themodel->Number(anent);
221   if (nument == 0) return;
222   IGESData_DirPart& DP = thedirs.ChangeValue(nument);
223 //                                            Remplissage du DirPart
224   v[0] = anent->TypeNumber();
225   v[1] = 0;               // numero en section P : calcule ulterieurement
226   if (anent->HasStructure())           v[2] = - themodel->DNum(anent->DirFieldEntity(3));
227   else                                 v[2] = 0;
228
229   IGESData_DefType linet = anent->DefLineFont();
230   if (linet == IGESData_DefReference)  v[3] = - themodel->DNum(anent->DirFieldEntity(4));
231   else if (linet == IGESData_DefValue) v[3] = anent->RankLineFont();
232   else                                 v[3] = 0;
233
234   IGESData_DefList levt = anent->DefLevel();
235   if (levt == IGESData_DefSeveral)     v[4] = - themodel->DNum(anent->DirFieldEntity(5));
236   else if (levt == IGESData_DefOne)    v[4] = anent->Level();
237   else                                 v[4] = 0;
238
239   IGESData_DefList viewt = anent->DefView();
240   if (viewt == IGESData_DefSeveral || viewt == IGESData_DefOne)
241     v[5]                                    = themodel->DNum(anent->DirFieldEntity(6));
242   else                                 v[5] = 0;
243
244   if (anent->HasTransf())              v[6] = themodel->DNum(anent->DirFieldEntity(7));
245   else                                 v[6] = 0;
246
247   if (anent->HasLabelDisplay())        v[7] = themodel->DNum(anent->DirFieldEntity(8));
248   else                                 v[7] = 0;
249
250   v[8] = anent->BlankStatus();
251   v[9] = anent->SubordinateStatus();
252   v[10] = anent->UseFlag();
253   v[11] = anent->HierarchyStatus();
254   v[12] = v[0];                      // type repete
255   v[13] = anent->LineWeightNumber();
256
257   IGESData_DefType colt = anent->DefColor();
258   if (colt == IGESData_DefReference)   v[14] = - themodel->DNum(anent->DirFieldEntity(13));
259   else if (colt == IGESData_DefValue)  v[14] = anent->RankColor();
260   else                                 v[14] = 0;
261
262   v[15] = 0;                        // nb lignes section P : calcule plus tard
263   v[16] = anent->FormNumber();
264
265   anent->CResValues(res1,res2);
266   Standard_Integer i; // svv Jan11 2000 : porting on DEC
267   for (i = 0; i < 8; i ++) label[i] = snum[i] = ' ';
268   if (anent->HasShortLabel()) {
269     Handle(TCollection_HAsciiString) slab = anent->ShortLabel();
270     for (i = 0; i < slab->Length(); i ++) label[i] = slab->Value(i+1);
271   }
272   if (anent->HasSubScriptNumber()) {
273     Standard_Integer sn = anent->SubScriptNumber();  // -> cadres a droite
274     snum[7] = '0';    i = 7;
275     while (sn != 0) {
276       snum[i] = (char) ((sn % 10) + 48);
277       sn = sn / 10;   i --;
278     }
279   }
280
281   DP.Init(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],
282           v[13],v[14],v[15],v[16],res1,res2,label,snum);
283 //  DP ChangeValue donc mis a jour d office
284   thestep = IGESData_ReadDir;
285 }
286
287     void IGESData_IGESWriter::OwnParams
288   (const Handle(IGESData_IGESEntity)& anent)
289 {
290   char text[20];
291   if (thesect != 3 && thestep != IGESData_ReadDir)
292     throw Interface_InterfaceError("IGESWriter : OwnParams");
293   thepnum.SetValue(themodel->Number(anent),thepars->Length()+1);
294   thecurr.Clear();
295   sprintf(text,"%d",anent->TypeNumber());
296   AddString(text);
297   thestep = IGESData_ReadOwn;
298 }
299
300     void IGESData_IGESWriter::Properties
301   (const Handle(IGESData_IGESEntity)& anent)
302 {
303   if (thesect != 3 && thestep != IGESData_ReadOwn)
304     throw Interface_InterfaceError("IGESWriter : Properties");
305   thestep = IGESData_ReadProps;
306   if (!anent->ArePresentProperties()) return;
307   Send(anent->NbProperties());
308   for (Interface_EntityIterator iter = anent->Properties();
309        iter.More(); iter.Next()) {
310     DeclareAndCast(IGESData_IGESEntity,localent,iter.Value());
311     Send(localent);
312   }
313 }
314
315     void IGESData_IGESWriter::Associativities
316   (const Handle(IGESData_IGESEntity)& anent)
317 {
318   if (thesect != 3 && thestep != IGESData_ReadOwn)
319     throw Interface_InterfaceError("IGESWriter : Associativities");
320   thestep = IGESData_ReadAssocs;
321   if (!anent->ArePresentAssociativities() && !anent->ArePresentProperties())
322     return;  // Properties suivent : ne pas les omettre !
323   Send(anent->NbAssociativities());
324   for (Interface_EntityIterator iter = anent->Associativities();
325        iter.More(); iter.Next()) {
326     DeclareAndCast(IGESData_IGESEntity,localent,iter.Value());
327     Send(localent);
328   }
329   thestep = IGESData_ReadAssocs;
330 }
331
332     void IGESData_IGESWriter::EndEntity ()
333 {
334   if (thesect != 3 && thestep != IGESData_ReadOwn)
335     throw Interface_InterfaceError("IGESWriter : EndEntity");
336   AddChar(theendm);
337   if (thecurr.Length() > 0) thepars->Append(thecurr.Moved());
338   thestep = IGESData_ReadEnd;
339 }
340
341 //  ....                    Alimentation des parametres                    ....
342
343     void IGESData_IGESWriter::AddString
344   (const Handle(TCollection_HAsciiString)& val, const Standard_Integer more)
345 {
346   if (val.IsNull()) return;
347   AddString (val->ToCString(),val->Length(),more);
348 }
349
350     void IGESData_IGESWriter::AddString
351   (const Standard_CString val, const Standard_Integer lnval,
352    const Standard_Integer more)
353 {
354   Standard_Integer lnstr = lnval;
355   if (lnstr <= 0)  lnstr = (Standard_Integer)strlen(val);
356   if (!thecurr.CanGet (lnstr + more + 1)) {
357 // + 1 (18-SEP-1996) pour etre sur que le separateur n est pas en tete de ligne
358     if (thesect < 3) thehead->Append(thecurr.Moved());
359     else             thepars->Append(thecurr.Moved());
360   }
361   Standard_Integer maxcars  = (thesect == 3 ? MaxcarsP : MaxcarsG);
362   Standard_Integer n2 = 0;
363 // ..  pb de taille limite (30-DEC-1996)
364   while (lnstr > maxcars) {
365     thecurr.Add (&val[n2],lnstr);
366     if (thesect < 3) thehead->Append(thecurr.Moved());
367     else             thepars->Append(thecurr.Moved());
368     n2 += maxcars;  lnstr -= maxcars;
369   }
370   thecurr.Add (&val[n2],lnstr);
371 }
372
373     void IGESData_IGESWriter::AddChar
374   (const Standard_Character val,
375    const Standard_Integer more)
376 {
377 //   1 seul caractere : cas particulier simplifie
378   char text[2];
379   text[0] = val;
380   text[1] = '\0';
381   if (!thecurr.CanGet (1 + more)) {
382     if (thesect < 3) thehead->Append(thecurr.Moved());
383     else             thepars->Append(thecurr.Moved());
384   }
385   thecurr.Add (text,1);
386 }
387
388
389     void IGESData_IGESWriter::SendVoid ()
390       {  AddChar(thesep);  }
391
392     void IGESData_IGESWriter::Send (const Standard_Integer val)
393 {
394   char text[20];
395   AddChar(thesep);
396   sprintf(text,"%d",val);
397   AddString(text);
398 }
399
400     void IGESData_IGESWriter::SendBoolean (const Standard_Boolean val)
401 {
402   AddChar(thesep);
403   if (val) AddString("1");
404   else     AddString("0");
405 }
406
407     void IGESData_IGESWriter::Send (const Standard_Real val)
408 {
409 //    Valeur flottante, expurgee de "0000" qui trainent et de "E+00"
410   char lval[24];
411   AddChar(thesep);
412   Standard_Integer lng = thefloatw.Write (val,lval);
413   AddString(lval,lng);
414 }
415
416     void IGESData_IGESWriter::Send (const Handle(TCollection_HAsciiString)& val)
417 {
418   AddChar(thesep);
419   if (val.IsNull()) return;
420   Standard_Integer lns = val->Length();
421   if (lns == 0) return;     // string vide : void vaut mieux que 0H
422   Handle(TCollection_HAsciiString) hol = new TCollection_HAsciiString(lns);
423   hol->AssignCat("H");  hol->AssignCat(val->ToCString());
424   AddString(hol);
425 }
426
427     void IGESData_IGESWriter::Send
428   (const Handle(IGESData_IGESEntity)& val, const Standard_Boolean negative)
429 {
430   Standard_Integer num = 0;
431   if (!val.IsNull()) num = themodel->DNum(val);
432   if (negative) num = -num;
433   Send(num);    // qui faut tout, une fois Entity convertie en Integer
434 }
435
436     void IGESData_IGESWriter::Send (const gp_XY&  val)
437       {  Send(val.X());  Send(val.Y());  }
438
439     void IGESData_IGESWriter::Send (const gp_XYZ& val)
440       {  Send(val.X());  Send(val.Y());  Send(val.Z());  }
441
442
443     void IGESData_IGESWriter::SendString (const Handle(TCollection_HAsciiString)& val)
444 {
445   AddChar(thesep);
446   AddString(val);    // envoi en l etat
447 }
448
449
450 //  ....                            Envoi final                            ....
451
452     Handle(TColStd_HSequenceOfHAsciiString) IGESData_IGESWriter::SectionStrings
453   (const Standard_Integer num) const
454 {
455   Handle(TColStd_HSequenceOfHAsciiString) res;
456   if (num == 1) res = thestar;
457   if (num == 2) res = thehead;
458   if (num >= 3) res = thepars;
459   return res;
460 }
461
462 static void writefnes (Standard_OStream& S, const Standard_CString ligne)
463 {
464   char val;
465   for (Standard_Integer i = 0; i < 80; i ++) {
466     if (ligne[i] == '\0') return;
467     val = (char)(ligne[i] ^ (150 + (i & 3)));
468     S << val;
469   }
470 }
471
472 Standard_Boolean IGESData_IGESWriter::Print (Standard_OStream& S) const
473 {
474 //  ATTENTION MODEFNES : si themodew = 10 ... alors on ecrit du FNES
475 //  quesaco ? fnes = iges + xor sur les caracteres (150,151,152,153,150...)
476 //   avec en plus une ligne qcq en tete ...
477 //  donc tous les 4 car.s, on fait un tour de modulo. ainsi a 64 et a 72 ...
478 //  On a une mini-routine qui ecrit un morceau de texte "en fnes", et les
479 //  blancs qui sont optimises (quand meme ...)
480
481   Standard_Boolean isGood = (S.good() );
482   Standard_Boolean fnes = (themodew >= 10);
483   if(!isGood)
484     return isGood;
485   char ligne[81];
486 #ifdef PATIENCELOG
487   Standard_Integer lignespatience = 1000;
488 #endif
489   char blancs[73];
490   Standard_Integer i; // svv Jan11 2000 : porting on DEC
491   for (i = 0; i < MaxcarsG; i ++) blancs[i] = ' ';
492   blancs[MaxcarsG] = '\0';
493   if (fnes)
494   {
495     for (i = 0; i < MaxcarsG; i ++)
496       blancs[i] = (char)(blancs[i] ^ (150 + (i & 3)));
497   }
498
499   if (thesect != 4) throw Interface_InterfaceError("IGESWriter not ready for Print");
500 //  Start Section (assez simple, somme toute). Attention si commentaires
501   Handle(TCollection_HAsciiString) line;
502   Standard_Integer nbs = 1;
503   if (thestar.IsNull()) {
504     if (fnes) {
505       S << "                              ***  EUCLID/STRIM  DESKTOP CLIPBOARD  ***"<<endl;
506       writefnes (S,"                                                                        S0000001");
507     }
508     else S<<"                                                                        S0000001";
509 //      123456789 123456789 123456789 123456789 123456789 123456789 123456789 12 
510     S << endl;
511   } else {
512     nbs = thestar->Length();
513     for (i = 1; i <= nbs; i ++) {
514       char finlin[20];
515       sprintf(finlin,"S%7.7d",i);
516       line = thestar->Value(i);
517
518       if (fnes) writefnes (S,line->ToCString());
519       else S << line->ToCString();
520 //    for (Standard_Integer k = line->Length()+1; k <= MaxcarsG; k ++)  S<<' ';
521       S << &blancs[line->Length()];
522       if (fnes) writefnes (S,finlin);
523       else S << finlin;  S << endl;
524     }
525   }
526 #ifdef PATIENCELOG
527   cout << "Global Section : " << flush;
528 #endif
529   isGood = S.good();
530 //  Global Section  :  convertie dans <thehead>
531   Standard_Integer nbg = thehead->Length();
532   for (i = 1; i <= nbg && isGood ;i++) {
533     char finlin[20];
534     sprintf(finlin,"G%7.7d",i);
535     line = thehead->Value(i);
536
537     if (fnes) writefnes (S,line->ToCString());
538     else S << line->ToCString();
539 //    for (Standard_Integer k = line->Length()+1; k <= MaxcarsG; k ++)  S<<' ';
540     S << &blancs[line->Length()];
541     if (fnes) writefnes (S,finlin);
542     else S << finlin;  S << endl;
543     isGood = S.good();
544   }
545   if(!isGood)
546     return isGood;
547 #ifdef PATIENCELOG
548   cout << nbg << " lines" << endl;
549 #endif
550
551 //  Directory Section
552   Standard_Integer nbd = thedirs.Upper();   // 0 -> NbEnts
553 #ifdef PATIENCELOG
554   cout << "\nDirectory section : " << nbd << " Entites" << endl;
555 #endif
556   for (i = 1; i <= nbd && isGood ; i ++) {
557     Standard_Integer v[17]; char res1[9],res2[9],lab[9],num[9];
558     thedirs.Value(i).Values(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],
559                             v[10],v[11],v[12],v[13],v[14],v[15],v[16],
560                             res1,res2,lab,num);
561     v[1]  = thepnum.Value(i);  // debut en P
562     v[15] = thepnum.Value(i+1)-thepnum.Value(i);  // nb de lignes en P
563     sprintf(ligne,"%8d%8d%8d%8d%8d%8d%8d%8d%2.2d%2.2d%2.2d%2.2dD%7.7d",
564             v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],
565             v[8],v[9],v[10],v[11] ,2*i-1);
566     if (fnes) writefnes (S,ligne);
567     else S << ligne;  S<< "\n";
568     sprintf(ligne,"%8d%8d%8d%8d%8d%8s%8s%8s%8sD%7.7d",
569             v[0],v[13],v[14],v[15],v[16],res1,res2,lab,num,2*i);
570     if (fnes) writefnes (S,ligne);
571     else S << ligne;  S<< "\n";
572 //    cout << "Ent.no "<<i<<" No en P "<<thepnum.Value(i)<<
573 //      " Lignes P:"<<thepnum.Value(i+1)-thepnum.Value(i)<<endl;
574 //    for (j = 0; j < 17; j ++) S<<v[j]<<" ";
575 //    S<<res1<<res2<<" label:"<<lab<<" subnum:"<<num<<endl;
576     isGood = S.good();
577   }
578   if(!isGood)
579     return isGood;
580 //  Parameter Section
581 #ifdef PATIENCELOG
582   cout<<" Parameter Section : "<<thepnum.Value(nbd)-1
583       <<" lines (* = 1000 lines) "<<flush;
584 #endif
585   
586   blancs[MaxcarsP] = '\0';
587   for (i = 1; i <= nbd && isGood; i ++) {
588     for (Standard_Integer j = thepnum.Value(i); j < thepnum.Value(i+1); j ++) {
589       char finlin[20];
590       sprintf(finlin," %7.7dP%7.7d",2*i-1,j);
591       line = thepars->Value(j);
592 //      line->LeftJustify(MaxcarsP,' ');  remplace par plus economique ! :
593
594       if (fnes) writefnes (S,line->ToCString());
595       else S << line->ToCString();
596 //      for (Standard_Integer k = line->Length()+1; k <= MaxcarsP; k ++)S<<' ';
597       S << &blancs[line->Length()];
598       if (fnes) writefnes (S,finlin);
599       else S << finlin;  S << endl;
600       isGood = S.good();
601 #ifdef PATIENCELOG
602       lignespatience --;
603       if (lignespatience <= 0) {  cout<<"*"<<flush;  lignespatience = 1000;  }
604 #endif
605     }
606   }
607   if(!isGood)
608     return isGood;
609 //  Terminal Section (pas trop compliquee, ma foi)
610   sprintf (ligne,
611     "S%7dG%7dD%7dP%7d                                        T0000001",
612            nbs,nbg,nbd*2,thepnum.Value(thepnum.Length())-1);
613 //   12345678- 16- 24- 32  56789 123456789 123456789 123456789 12
614   if (fnes) writefnes (S,ligne);
615   else S << ligne;  S<< "\n";
616   S.flush();
617   isGood = S.good();
618 #ifdef PATIENCELOG
619   cout <<"\n Section T (lines counts) : G "<<nbg<<"   D "<<nbd
620        <<"   P "<<thepnum.Value(thepnum.Length())-1<<"   T 1"<<endl;
621 #endif
622   return isGood;
623 }