1 // Copyright (c) 1999-2012 OPEN CASCADE SAS
3 // The content of this file is subject to the Open CASCADE Technology Public
4 // License Version 6.5 (the "License"). You may not use the content of this file
5 // except in compliance with the License. Please obtain a copy of the License
6 // at http://www.opencascade.org and read it completely before using this file.
8 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
9 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11 // The Original Code and all software distributed under the License is
12 // distributed on an "AS IS" basis, without warranty of any kind, and the
13 // Initial Developer hereby disclaims all such warranties, including without
14 // limitation, any warranties of merchantability, fitness for a particular
15 // purpose or non-infringement. Please see the License for the specific terms
16 // and conditions governing the rights and limitations under the License.
18 #include <IGESData_IGESWriter.ixx>
19 #include <IGESData_DefType.hxx>
20 #include <IGESData_DirPart.hxx>
21 #include <Interface_ParamSet.hxx>
22 #include <Interface_ReportEntity.hxx>
23 #include <Interface_EntityIterator.hxx>
24 #include <Interface_InterfaceError.hxx>
25 #include <Interface_Macros.hxx>
26 #include <Message_Messenger.hxx>
27 #include <Message.hxx>
29 #include <IGESData_WriterLib.hxx>
30 #include <IGESData_ReadWriteModule.hxx>
31 #include <IGESData_UndefinedEntity.hxx>
33 #include <IGESData_LineFontEntity.hxx>
34 #include <IGESData_LevelListEntity.hxx>
35 #include <IGESData_TransfEntity.hxx>
36 #include <IGESData_ViewKindEntity.hxx>
37 #include <IGESData_LabelDisplayEntity.hxx>
38 #include <IGESData_ColorEntity.hxx>
40 #include <TCollection_AsciiString.hxx>
41 #include <Interface_FileParameter.hxx>
42 #include <Interface_ParamList.hxx>
44 #include <Standard_PCharacter.hxx>
52 // Constructeur complet : taille OK, et se remplit depuis le modele en direct
54 IGESData_IGESWriter::IGESData_IGESWriter
55 (const Handle(IGESData_IGESModel)& amodel)
56 : thedirs(0,amodel->NbEntities()) , thepnum(1,amodel->NbEntities()+1),
57 thecurr (MaxcarsG+1) , themodew (0) , thefloatw (9)
60 thehead = new TColStd_HSequenceOfHAsciiString();
63 thepars = new TColStd_HSequenceOfHAsciiString();
64 thepnum.SetValue(1,1); // debut des parametres de la 1re entite
67 // Format flottant : cf FloatWriter
70 IGESData_IGESWriter::IGESData_IGESWriter ()
71 : thedirs (0,0) , thepnum (1,1) , thecurr (MaxcarsG+1) , thefloatw (9) { }
73 IGESData_IGESWriter::IGESData_IGESWriter (const IGESData_IGESWriter& )
74 : thedirs (0,0) , thepnum (1,1) , thecurr (MaxcarsG+1) , thefloatw (9) { }
77 // .... Controle d Envoi des Flottants ....
79 Interface_FloatWriter& IGESData_IGESWriter::FloatWriter ()
80 { return thefloatw; } // s y reporter
82 Standard_Integer& IGESData_IGESWriter::WriteMode ()
85 // #####################################################################
86 // ######## GENERATION DU FICHIER ########
88 //=======================================================================
89 //function : SendStartLine
91 //=======================================================================
92 void IGESData_IGESWriter::SendStartLine (const Standard_CString startline)
94 Standard_PCharacter pstartline;
96 pstartline=(Standard_PCharacter)startline;
98 Standard_Size lst = strlen (startline);
100 if (thestar.IsNull()) thestar = new TColStd_HSequenceOfHAsciiString();
101 if (lst <= (Standard_Size)MaxcarsG) {
102 thestar->Append (new TCollection_HAsciiString(startline));
105 // Trop longue : on passe par bouts
106 char startchar = startline[MaxcarsG];
107 pstartline[MaxcarsG] = '\0';
108 SendStartLine(startline);
109 pstartline[MaxcarsG] = startchar;
110 SendStartLine (&startline[MaxcarsG]);
113 void IGESData_IGESWriter::SendModel
114 (const Handle(IGESData_Protocol)& protocol)
116 Handle(Message_Messenger) sout = Message::DefaultMessenger();
117 IGESData_WriterLib lib(protocol);
119 Standard_Integer nb = themodel->NbEntities();
121 sout<< " IGESWriter : " << nb << " Entities (* = 1000 Ent.s)" << endl;
124 Standard_Integer ns = themodel->NbStartLines();
125 Standard_Integer i; // svv Jan11 2000 : porting on DEC
126 for (i = 1; i <= ns; i ++) SendStartLine (themodel->StartLine(i));
127 SectionG (themodel->GlobalSection());
129 for (i = 1; i <= nb; i ++) {
130 Handle(IGESData_IGESEntity) ent = themodel->Entity(i);
131 Handle(IGESData_IGESEntity) cnt = ent;
133 if (i % 1000 == 1) cout << "*" << flush;
135 // Attention aux cas d erreur : contenu redefini
136 if (themodel->IsRedefinedContent(i)) {
137 sout << " -- IGESWriter : Erroneous Entity N0."<<i<<" --"<<endl;
138 Handle(Interface_ReportEntity) rep = themodel->ReportEntity(i);
139 if (!rep.IsNull()) cnt = GetCasted(IGESData_IGESEntity,rep->Content());
140 if (cnt.IsNull()) cnt = ent; // secours
144 OwnParams (ent); // preparation : porte sur le vrai <ent> ...
146 // Envoi proprement dit des Parametres proprement definis
147 Handle(IGESData_ReadWriteModule) module; Standard_Integer CN;
149 if (lib.Select(cnt,module,CN))
150 module->WriteOwnParams (CN,cnt,*this);
151 else if (cnt->IsKind(STANDARD_TYPE(IGESData_UndefinedEntity))) {
152 DeclareAndCast(IGESData_UndefinedEntity,undent,cnt);
153 undent->WriteOwnParams (*this);
155 else sout<<" -- IGESWriter : Not Processed for n0."<<i<<" in file, Type "
156 <<cnt->TypeNumber()<<" Form "<<cnt->FormNumber()<<endl;
158 Associativities (cnt);
163 cout << " Envoi des Entites Termine"<<endl;
169 void IGESData_IGESWriter::SectionS ()
171 if (thesect != 0) Interface_InterfaceError::Raise("IGESWriter : SectionS");
175 void IGESData_IGESWriter::SectionG (const IGESData_GlobalSection& header)
177 if (thesect != 1) Interface_InterfaceError::Raise("IGESWriter : SectionG");
179 thesep = header.Separator();
180 theendm = header.EndMark();
181 thecurr.SetMax (MaxcarsG);
182 // Important : les Parametres sont sortis sous leur forme definitive
183 // (c-a-d Hollerith pour les Textes ...)
184 Handle(Interface_ParamSet) gl = header.Params();
185 Standard_Integer nb = gl->NbParams();
186 for (Standard_Integer i = 1; i <= nb; i ++) {
187 const Interface_FileParameter& FP = gl->Param(i);
188 AddString(FP.CValue());
189 if (i < nb) AddChar(thesep);
190 else AddChar(theendm);
192 if (thecurr.Length() > 0) thehead->Append(thecurr.Moved());
195 void IGESData_IGESWriter::SectionsDP ()
197 if (thesect != 2) Interface_InterfaceError::Raise("IGESWriter : SectionsDP");
199 thecurr.SetMax (MaxcarsP);
200 thestep = IGESData_ReadEnd;
203 void IGESData_IGESWriter::SectionT ()
205 if (thesect != 3) Interface_InterfaceError::Raise("IGESWriter : SectionT");
207 thepnum.SetValue(thepnum.Length(),thepars->Length()+1);
211 void IGESData_IGESWriter::DirPart
212 (const Handle(IGESData_IGESEntity)& anent)
214 if (thesect != 3 && thestep != IGESData_ReadEnd)
215 Interface_InterfaceError::Raise("IGESWriter : DirPart");
216 Standard_Integer v[17]; Standard_Character res1[9],res2[9],label[9],snum[9];
217 Standard_Integer nument = themodel->Number(anent);
218 if (nument == 0) return;
219 IGESData_DirPart& DP = thedirs.ChangeValue(nument);
220 // Remplissage du DirPart
221 v[0] = anent->TypeNumber();
222 v[1] = 0; // numero en section P : calcule ulterieurement
223 if (anent->HasStructure()) v[2] = - themodel->DNum(anent->DirFieldEntity(3));
226 IGESData_DefType linet = anent->DefLineFont();
227 if (linet == IGESData_DefReference) v[3] = - themodel->DNum(anent->DirFieldEntity(4));
228 else if (linet == IGESData_DefValue) v[3] = anent->RankLineFont();
231 IGESData_DefList levt = anent->DefLevel();
232 if (levt == IGESData_DefSeveral) v[4] = - themodel->DNum(anent->DirFieldEntity(5));
233 else if (levt == IGESData_DefOne) v[4] = anent->Level();
236 IGESData_DefList viewt = anent->DefView();
237 if (viewt == IGESData_DefSeveral || viewt == IGESData_DefOne)
238 v[5] = themodel->DNum(anent->DirFieldEntity(6));
241 if (anent->HasTransf()) v[6] = themodel->DNum(anent->DirFieldEntity(7));
244 if (anent->HasLabelDisplay()) v[7] = themodel->DNum(anent->DirFieldEntity(8));
247 v[8] = anent->BlankStatus();
248 v[9] = anent->SubordinateStatus();
249 v[10] = anent->UseFlag();
250 v[11] = anent->HierarchyStatus();
251 v[12] = v[0]; // type repete
252 v[13] = anent->LineWeightNumber();
254 IGESData_DefType colt = anent->DefColor();
255 if (colt == IGESData_DefReference) v[14] = - themodel->DNum(anent->DirFieldEntity(13));
256 else if (colt == IGESData_DefValue) v[14] = anent->RankColor();
259 v[15] = 0; // nb lignes section P : calcule plus tard
260 v[16] = anent->FormNumber();
262 anent->CResValues(res1,res2);
263 Standard_Integer i; // svv Jan11 2000 : porting on DEC
264 for (i = 0; i < 8; i ++) label[i] = snum[i] = ' ';
265 if (anent->HasShortLabel()) {
266 Handle(TCollection_HAsciiString) slab = anent->ShortLabel();
267 for (i = 0; i < slab->Length(); i ++) label[i] = slab->Value(i+1);
269 if (anent->HasSubScriptNumber()) {
270 Standard_Integer sn = anent->SubScriptNumber(); // -> cadres a droite
271 snum[7] = '0'; i = 7;
273 snum[i] = (char) ((sn % 10) + 48);
278 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],
279 v[13],v[14],v[15],v[16],res1,res2,label,snum);
280 // DP ChangeValue donc mis a jour d office
281 thestep = IGESData_ReadDir;
284 void IGESData_IGESWriter::OwnParams
285 (const Handle(IGESData_IGESEntity)& anent)
288 if (thesect != 3 && thestep != IGESData_ReadDir)
289 Interface_InterfaceError::Raise("IGESWriter : OwnParams");
290 thepnum.SetValue(themodel->Number(anent),thepars->Length()+1);
292 sprintf(text,"%d",anent->TypeNumber());
294 thestep = IGESData_ReadOwn;
297 void IGESData_IGESWriter::Properties
298 (const Handle(IGESData_IGESEntity)& anent)
300 if (thesect != 3 && thestep != IGESData_ReadOwn)
301 Interface_InterfaceError::Raise("IGESWriter : Properties");
302 thestep = IGESData_ReadProps;
303 if (!anent->ArePresentProperties()) return;
304 Send(anent->NbProperties());
305 for (Interface_EntityIterator iter = anent->Properties();
306 iter.More(); iter.Next()) {
307 DeclareAndCast(IGESData_IGESEntity,localent,iter.Value());
312 void IGESData_IGESWriter::Associativities
313 (const Handle(IGESData_IGESEntity)& anent)
315 if (thesect != 3 && thestep != IGESData_ReadOwn)
316 Interface_InterfaceError::Raise("IGESWriter : Associativities");
317 thestep = IGESData_ReadAssocs;
318 if (!anent->ArePresentAssociativities() && !anent->ArePresentProperties())
319 return; // Properties suivent : ne pas les omettre !
320 Send(anent->NbAssociativities());
321 for (Interface_EntityIterator iter = anent->Associativities();
322 iter.More(); iter.Next()) {
323 DeclareAndCast(IGESData_IGESEntity,localent,iter.Value());
326 thestep = IGESData_ReadAssocs;
329 void IGESData_IGESWriter::EndEntity ()
331 if (thesect != 3 && thestep != IGESData_ReadOwn)
332 Interface_InterfaceError::Raise("IGESWriter : EndEntity");
334 if (thecurr.Length() > 0) thepars->Append(thecurr.Moved());
335 thestep = IGESData_ReadEnd;
338 // .... Alimentation des parametres ....
340 void IGESData_IGESWriter::AddString
341 (const Handle(TCollection_HAsciiString)& val, const Standard_Integer more)
343 if (val.IsNull()) return;
344 AddString (val->ToCString(),val->Length(),more);
347 void IGESData_IGESWriter::AddString
348 (const Standard_CString val, const Standard_Integer lnval,
349 const Standard_Integer more)
351 Standard_Integer lnstr = lnval;
352 if (lnstr <= 0) lnstr = (Standard_Integer)strlen(val);
353 if (!thecurr.CanGet (lnstr + more + 1)) {
354 // + 1 (18-SEP-1996) pour etre sur que le separateur n est pas en tete de ligne
355 if (thesect < 3) thehead->Append(thecurr.Moved());
356 else thepars->Append(thecurr.Moved());
358 Standard_Integer maxcars = (thesect == 3 ? MaxcarsP : MaxcarsG);
359 Standard_Integer n2 = 0;
360 // .. pb de taille limite (30-DEC-1996)
361 while (lnstr > maxcars) {
362 thecurr.Add (&val[n2],lnstr);
363 if (thesect < 3) thehead->Append(thecurr.Moved());
364 else thepars->Append(thecurr.Moved());
365 n2 += maxcars; lnstr -= maxcars;
367 thecurr.Add (&val[n2],lnstr);
370 void IGESData_IGESWriter::AddChar
371 (const Standard_Character val,
372 const Standard_Integer more)
374 // 1 seul caractere : cas particulier simplifie
378 if (!thecurr.CanGet (1 + more)) {
379 if (thesect < 3) thehead->Append(thecurr.Moved());
380 else thepars->Append(thecurr.Moved());
382 thecurr.Add (text,1);
386 void IGESData_IGESWriter::SendVoid ()
389 void IGESData_IGESWriter::Send (const Standard_Integer val)
393 sprintf(text,"%d",val);
397 void IGESData_IGESWriter::SendBoolean (const Standard_Boolean val)
400 if (val) AddString("1");
404 void IGESData_IGESWriter::Send (const Standard_Real val)
406 // Valeur flottante, expurgee de "0000" qui trainent et de "E+00"
409 Standard_Integer lng = thefloatw.Write (val,lval);
413 void IGESData_IGESWriter::Send (const Handle(TCollection_HAsciiString)& val)
416 if (val.IsNull()) return;
417 Standard_Integer lns = val->Length();
418 if (lns == 0) return; // string vide : void vaut mieux que 0H
419 Handle(TCollection_HAsciiString) hol = new TCollection_HAsciiString(lns);
420 hol->AssignCat("H"); hol->AssignCat(val->ToCString());
424 void IGESData_IGESWriter::Send
425 (const Handle(IGESData_IGESEntity)& val, const Standard_Boolean negative)
427 Standard_Integer num = 0;
428 if (!val.IsNull()) num = themodel->DNum(val);
429 if (negative) num = -num;
430 Send(num); // qui faut tout, une fois Entity convertie en Integer
433 void IGESData_IGESWriter::Send (const gp_XY& val)
434 { Send(val.X()); Send(val.Y()); }
436 void IGESData_IGESWriter::Send (const gp_XYZ& val)
437 { Send(val.X()); Send(val.Y()); Send(val.Z()); }
440 void IGESData_IGESWriter::SendString (const Handle(TCollection_HAsciiString)& val)
443 AddString(val); // envoi en l etat
447 // .... Envoi final ....
449 Handle(TColStd_HSequenceOfHAsciiString) IGESData_IGESWriter::SectionStrings
450 (const Standard_Integer num) const
452 Handle(TColStd_HSequenceOfHAsciiString) res;
453 if (num == 1) res = thestar;
454 if (num == 2) res = thehead;
455 if (num >= 3) res = thepars;
459 static void writefnes (Standard_OStream& S, const Standard_CString ligne)
462 for (Standard_Integer i = 0; i < 80; i ++) {
463 if (ligne[i] == '\0') return;
464 val = ligne[i] ^ (150 + (i & 3));
469 Standard_Boolean IGESData_IGESWriter::Print (Standard_OStream& S) const
471 // ATTENTION MODEFNES : si themodew = 10 ... alors on ecrit du FNES
472 // quesaco ? fnes = iges + xor sur les caracteres (150,151,152,153,150...)
473 // avec en plus une ligne qcq en tete ...
474 // donc tous les 4 car.s, on fait un tour de modulo. ainsi a 64 et a 72 ...
475 // On a une mini-routine qui ecrit un morceau de texte "en fnes", et les
476 // blancs qui sont optimises (quand meme ...)
478 Standard_Boolean isGood = (S.good() );
479 Standard_Boolean fnes = (themodew >= 10);
484 Standard_Integer lignespatience = 1000;
487 Standard_Integer i; // svv Jan11 2000 : porting on DEC
488 for (i = 0; i < MaxcarsG; i ++) blancs[i] = ' ';
489 blancs[MaxcarsG] = '\0';
490 if (fnes) for (i = 0; i < MaxcarsG; i ++) blancs[i] = blancs[i] ^ (150 + (i & 3));
492 if (thesect != 4) Interface_InterfaceError::Raise
493 ("IGESWriter not ready for Print");
494 // Start Section (assez simple, somme toute). Attention si commentaires
495 Handle(TCollection_HAsciiString) line;
496 Standard_Integer nbs = 1;
497 if (thestar.IsNull()) {
499 S << " *** EUCLID/STRIM DESKTOP CLIPBOARD ***"<<endl;
500 writefnes (S," S0000001");
503 // 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12
506 nbs = thestar->Length();
507 for (i = 1; i <= nbs; i ++) {
509 sprintf(finlin,"S%7.7d",i);
510 line = thestar->Value(i);
512 if (fnes) writefnes (S,line->ToCString());
513 else S << line->ToCString();
514 // for (Standard_Integer k = line->Length()+1; k <= MaxcarsG; k ++) S<<' ';
515 S << &blancs[line->Length()];
516 if (fnes) writefnes (S,finlin);
517 else S << finlin; S << endl;
521 cout << "Global Section : " << flush;
524 // Global Section : convertie dans <thehead>
525 Standard_Integer nbg = thehead->Length();
526 for (i = 1; i <= nbg && isGood ;i++) {
528 sprintf(finlin,"G%7.7d",i);
529 line = thehead->Value(i);
531 if (fnes) writefnes (S,line->ToCString());
532 else S << line->ToCString();
533 // for (Standard_Integer k = line->Length()+1; k <= MaxcarsG; k ++) S<<' ';
534 S << &blancs[line->Length()];
535 if (fnes) writefnes (S,finlin);
536 else S << finlin; S << endl;
542 cout << nbg << " lines" << endl;
546 Standard_Integer nbd = thedirs.Upper(); // 0 -> NbEnts
548 cout << "\nDirectory section : " << nbd << " Entites" << endl;
550 for (i = 1; i <= nbd && isGood ; i ++) {
551 Standard_Integer v[17]; char res1[9],res2[9],lab[9],num[9];
552 thedirs.Value(i).Values(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],
553 v[10],v[11],v[12],v[13],v[14],v[15],v[16],
555 v[1] = thepnum.Value(i); // debut en P
556 v[15] = thepnum.Value(i+1)-thepnum.Value(i); // nb de lignes en P
557 sprintf(ligne,"%8d%8d%8d%8d%8d%8d%8d%8d%2.2d%2.2d%2.2d%2.2dD%7.7d",
558 v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],
559 v[8],v[9],v[10],v[11] ,2*i-1);
560 if (fnes) writefnes (S,ligne);
561 else S << ligne; S<< "\n";
562 sprintf(ligne,"%8d%8d%8d%8d%8d%8s%8s%8s%8sD%7.7d",
563 v[0],v[13],v[14],v[15],v[16],res1,res2,lab,num,2*i);
564 if (fnes) writefnes (S,ligne);
565 else S << ligne; S<< "\n";
566 // cout << "Ent.no "<<i<<" No en P "<<thepnum.Value(i)<<
567 // " Lignes P:"<<thepnum.Value(i+1)-thepnum.Value(i)<<endl;
568 // for (j = 0; j < 17; j ++) S<<v[j]<<" ";
569 // S<<res1<<res2<<" label:"<<lab<<" subnum:"<<num<<endl;
576 cout<<" Parameter Section : "<<thepnum.Value(nbd)-1
577 <<" lines (* = 1000 lines) "<<flush;
580 blancs[MaxcarsP] = '\0';
581 for (i = 1; i <= nbd && isGood; i ++) {
582 for (Standard_Integer j = thepnum.Value(i); j < thepnum.Value(i+1); j ++) {
584 sprintf(finlin," %7.7dP%7.7d",2*i-1,j);
585 line = thepars->Value(j);
586 // line->LeftJustify(MaxcarsP,' '); remplace par plus economique ! :
588 if (fnes) writefnes (S,line->ToCString());
589 else S << line->ToCString();
590 // for (Standard_Integer k = line->Length()+1; k <= MaxcarsP; k ++)S<<' ';
591 S << &blancs[line->Length()];
592 if (fnes) writefnes (S,finlin);
593 else S << finlin; S << endl;
597 if (lignespatience <= 0) { cout<<"*"<<flush; lignespatience = 1000; }
603 // Terminal Section (pas trop compliquee, ma foi)
605 "S%7dG%7dD%7dP%7d T0000001",
606 nbs,nbg,nbd*2,thepnum.Value(thepnum.Length())-1);
607 // 12345678- 16- 24- 32 56789 123456789 123456789 123456789 12
608 if (fnes) writefnes (S,ligne);
609 else S << ligne; S<< "\n";
613 cout <<"\n Section T (lines counts) : G "<<nbg<<" D "<<nbd
614 <<" P "<<thepnum.Value(thepnum.Length())-1<<" T 1"<<endl;