Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/graphs/planarity/graphDrawPlanar_Extensions.c
4057 views
1
/*
2
Planarity-Related Graph Algorithms Project
3
Copyright (c) 1997-2010, John M. Boyer
4
All rights reserved. Includes a reference implementation of the following:
5
6
* John M. Boyer. "Simplified O(n) Algorithms for Planar Graph Embedding,
7
Kuratowski Subgraph Isolation, and Related Problems". Ph.D. Dissertation,
8
University of Victoria, 2001.
9
10
* John M. Boyer and Wendy J. Myrvold. "On the Cutting Edge: Simplified O(n)
11
Planarity by Edge Addition". Journal of Graph Algorithms and Applications,
12
Vol. 8, No. 3, pp. 241-273, 2004.
13
14
* John M. Boyer. "A New Method for Efficiently Generating Planar Graph
15
Visibility Representations". In P. Eades and P. Healy, editors,
16
Proceedings of the 13th International Conference on Graph Drawing 2005,
17
Lecture Notes Comput. Sci., Volume 3843, pp. 508-511, Springer-Verlag, 2006.
18
19
Redistribution and use in source and binary forms, with or without modification,
20
are permitted provided that the following conditions are met:
21
22
* Redistributions of source code must retain the above copyright notice, this
23
list of conditions and the following disclaimer.
24
25
* Redistributions in binary form must reproduce the above copyright notice, this
26
list of conditions and the following disclaimer in the documentation and/or
27
other materials provided with the distribution.
28
29
* Neither the name of the Planarity-Related Graph Algorithms Project nor the names
30
of its contributors may be used to endorse or promote products derived from this
31
software without specific prior written permission.
32
33
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
37
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
40
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
*/
44
45
#include <stdlib.h>
46
47
#include "graphDrawPlanar.private.h"
48
#include "graphDrawPlanar.h"
49
50
extern void _CollectDrawingData(DrawPlanarContext *context, int RootVertex, int W, int WPrevLink);
51
extern int _BreakTie(DrawPlanarContext *context, int BicompRoot, int W, int WPrevLink);
52
53
extern int _ComputeVisibilityRepresentation(DrawPlanarContext *context);
54
extern int _CheckVisibilityRepresentationIntegrity(DrawPlanarContext *context);
55
56
/* Forward declarations of local functions */
57
58
void _DrawPlanar_ClearStructures(DrawPlanarContext *context);
59
int _DrawPlanar_CreateStructures(DrawPlanarContext *context);
60
int _DrawPlanar_InitStructures(DrawPlanarContext *context);
61
62
/* Forward declarations of overloading functions */
63
64
int _DrawPlanar_MergeBicomps(graphP theGraph, int I, int RootVertex, int W, int WPrevLink);
65
int _DrawPlanar_HandleInactiveVertex(graphP theGraph, int BicompRoot, int *pW, int *pWPrevLink);
66
int _DrawPlanar_EmbedPostprocess(graphP theGraph, int I, int edgeEmbeddingResult);
67
int _DrawPlanar_CheckEmbeddingIntegrity(graphP theGraph, graphP origGraph);
68
int _DrawPlanar_CheckObstructionIntegrity(graphP theGraph, graphP origGraph);
69
70
void _DrawPlanar_InitGraphNode(graphP theGraph, int I);
71
void _DrawPlanar_InitVertexRec(graphP theGraph, int I);
72
void _InitDrawGraphNode(DrawPlanarContext *context, int I);
73
void _InitDrawVertexRec(DrawPlanarContext *context, int I);
74
75
int _DrawPlanar_InitGraph(graphP theGraph, int N);
76
void _DrawPlanar_ReinitializeGraph(graphP theGraph);
77
int _DrawPlanar_EnsureArcCapacity(graphP theGraph, int requiredArcCapacity);
78
int _DrawPlanar_SortVertices(graphP theGraph);
79
80
int _DrawPlanar_ReadPostprocess(graphP theGraph, void *extraData, long extraDataSize);
81
int _DrawPlanar_WritePostprocess(graphP theGraph, void **pExtraData, long *pExtraDataSize);
82
83
/* Forward declarations of functions used by the extension system */
84
85
void *_DrawPlanar_DupContext(void *pContext, void *theGraph);
86
void _DrawPlanar_FreeContext(void *);
87
88
/****************************************************************************
89
* DRAWPLANAR_ID - the variable used to hold the integer identifier for this
90
* extension, enabling this feature's extension context to be distinguished
91
* from other features' extension contexts that may be attached to a graph.
92
****************************************************************************/
93
94
int DRAWPLANAR_ID = 0;
95
96
/****************************************************************************
97
gp_AttachDrawPlanar()
98
99
This function adjusts the graph data structure to attach the planar graph
100
drawing feature.
101
102
To activate this feature during gp_Embed(), use EMBEDFLAGS_DRAWPLANAR.
103
104
This method may be called immediately after gp_New() in the case of
105
invoking gp_Read(). For generating graphs, gp_InitGraph() can be invoked
106
before or after this enabling method. This method detects if the core
107
graph has already been initialized, and if so, it will initialize the
108
additional data structures specific to planar graph drawing. This makes
109
it possible to invoke gp_New() and gp_InitGraph() together, and then attach
110
this feature only if it is requested at run-time.
111
112
Returns OK for success, NOTOK for failure.
113
****************************************************************************/
114
115
int gp_AttachDrawPlanar(graphP theGraph)
116
{
117
DrawPlanarContext *context = NULL;
118
119
// If the drawing feature has already been attached to the graph,
120
// then there is no need to attach it again
121
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
122
if (context != NULL)
123
{
124
return OK;
125
}
126
127
// Allocate a new extension context
128
context = (DrawPlanarContext *) malloc(sizeof(DrawPlanarContext));
129
if (context == NULL)
130
{
131
return NOTOK;
132
}
133
134
// First, tell the context that it is not initialized
135
context->initialized = 0;
136
137
// Save a pointer to theGraph in the context
138
context->theGraph = theGraph;
139
140
// Put the overload functions into the context function table.
141
// gp_AddExtension will overload the graph's functions with these, and
142
// return the base function pointers in the context function table
143
memset(&context->functions, 0, sizeof(graphFunctionTable));
144
145
context->functions.fpMergeBicomps = _DrawPlanar_MergeBicomps;
146
context->functions.fpHandleInactiveVertex = _DrawPlanar_HandleInactiveVertex;
147
context->functions.fpEmbedPostprocess = _DrawPlanar_EmbedPostprocess;
148
context->functions.fpCheckEmbeddingIntegrity = _DrawPlanar_CheckEmbeddingIntegrity;
149
context->functions.fpCheckObstructionIntegrity = _DrawPlanar_CheckObstructionIntegrity;
150
151
context->functions.fpInitGraphNode = _DrawPlanar_InitGraphNode;
152
context->functions.fpInitVertexRec = _DrawPlanar_InitVertexRec;
153
154
context->functions.fpInitGraph = _DrawPlanar_InitGraph;
155
context->functions.fpReinitializeGraph = _DrawPlanar_ReinitializeGraph;
156
context->functions.fpEnsureArcCapacity = _DrawPlanar_EnsureArcCapacity;
157
context->functions.fpSortVertices = _DrawPlanar_SortVertices;
158
159
context->functions.fpReadPostprocess = _DrawPlanar_ReadPostprocess;
160
context->functions.fpWritePostprocess = _DrawPlanar_WritePostprocess;
161
162
_DrawPlanar_ClearStructures(context);
163
164
// Store the Draw context, including the data structure and the
165
// function pointers, as an extension of the graph
166
if (gp_AddExtension(theGraph, &DRAWPLANAR_ID, (void *) context,
167
_DrawPlanar_DupContext, _DrawPlanar_FreeContext,
168
&context->functions) != OK)
169
{
170
_DrawPlanar_FreeContext(context);
171
return NOTOK;
172
}
173
174
// Create the Draw-specific structures if the size of the graph is known
175
// Attach functions are typically invoked after gp_New(), but if a graph
176
// extension must be attached before gp_Read(), then the attachment
177
// also happens before gp_InitGraph() because gp_Read() invokes init only
178
// after it reads the order N of the graph. Hence, this attach call would
179
// occur when N==0 in the case of gp_Read().
180
// But if a feature is attached after gp_InitGraph(), then N > 0 and so we
181
// need to create and initialize all the custom data structures
182
if (theGraph->N > 0)
183
{
184
if (_DrawPlanar_CreateStructures(context) != OK ||
185
_DrawPlanar_InitStructures(context) != OK)
186
{
187
_DrawPlanar_FreeContext(context);
188
return NOTOK;
189
}
190
}
191
192
return OK;
193
}
194
195
/********************************************************************
196
gp_DetachDrawPlanar()
197
********************************************************************/
198
199
int gp_DetachDrawPlanar(graphP theGraph)
200
{
201
return gp_RemoveExtension(theGraph, DRAWPLANAR_ID);
202
}
203
204
/********************************************************************
205
_DrawPlanar_ClearStructures()
206
********************************************************************/
207
208
void _DrawPlanar_ClearStructures(DrawPlanarContext *context)
209
{
210
if (!context->initialized)
211
{
212
// Before initialization, the pointers are stray, not NULL
213
// Once NULL or allocated, free() or LCFree() can do the job
214
context->G = NULL;
215
context->V = NULL;
216
217
context->initialized = 1;
218
}
219
else
220
{
221
if (context->G != NULL)
222
{
223
free(context->G);
224
context->G = NULL;
225
}
226
if (context->V != NULL)
227
{
228
free(context->V);
229
context->V = NULL;
230
}
231
}
232
}
233
234
/********************************************************************
235
_DrawPlanar_CreateStructures()
236
Create uninitialized structures for the vertex and graph node
237
levels, and initialized structures for the graph level
238
********************************************************************/
239
int _DrawPlanar_CreateStructures(DrawPlanarContext *context)
240
{
241
int N = context->theGraph->N;
242
int Gsize = context->theGraph->edgeOffset + context->theGraph->arcCapacity;
243
244
if (N <= 0)
245
return NOTOK;
246
247
if ((context->G = (DrawPlanar_GraphNodeP) malloc(Gsize*sizeof(DrawPlanar_GraphNode))) == NULL ||
248
(context->V = (DrawPlanar_VertexRecP) malloc(N*sizeof(DrawPlanar_VertexRec))) == NULL
249
)
250
{
251
return NOTOK;
252
}
253
254
return OK;
255
}
256
257
/********************************************************************
258
_DrawPlanar_InitStructures()
259
Intended to be called when N>0.
260
Initializes vertex and graph node levels only. Graph level is
261
already initialized in _CreateStructures()
262
********************************************************************/
263
int _DrawPlanar_InitStructures(DrawPlanarContext *context)
264
{
265
int I, N = context->theGraph->N;
266
int Gsize = context->theGraph->edgeOffset + context->theGraph->arcCapacity;
267
268
if (N <= 0)
269
return NOTOK;
270
271
for (I = 0; I < Gsize; I++)
272
_InitDrawGraphNode(context, I);
273
274
for (I = 0; I < N; I++)
275
_InitDrawVertexRec(context, I);
276
277
return OK;
278
}
279
280
/********************************************************************
281
_DrawPlanar_DupContext()
282
********************************************************************/
283
284
void *_DrawPlanar_DupContext(void *pContext, void *theGraph)
285
{
286
DrawPlanarContext *context = (DrawPlanarContext *) pContext;
287
DrawPlanarContext *newContext = (DrawPlanarContext *) malloc(sizeof(DrawPlanarContext));
288
289
if (newContext != NULL)
290
{
291
int N = ((graphP) theGraph)->N;
292
int Gsize = ((graphP) theGraph)->edgeOffset + ((graphP) theGraph)->arcCapacity;
293
294
*newContext = *context;
295
296
newContext->theGraph = (graphP) theGraph;
297
298
newContext->initialized = 0;
299
_DrawPlanar_ClearStructures(newContext);
300
if (N > 0)
301
{
302
if (_DrawPlanar_CreateStructures(newContext) != OK)
303
{
304
_DrawPlanar_FreeContext(newContext);
305
return NULL;
306
}
307
308
// Initialize custom data structures by copying
309
memcpy(newContext->G, context->G, Gsize*sizeof(DrawPlanar_GraphNode));
310
memcpy(newContext->V, context->V, N*sizeof(DrawPlanar_VertexRec));
311
}
312
}
313
314
return newContext;
315
}
316
317
/********************************************************************
318
_DrawPlanar_FreeContext()
319
********************************************************************/
320
321
void _DrawPlanar_FreeContext(void *pContext)
322
{
323
DrawPlanarContext *context = (DrawPlanarContext *) pContext;
324
325
_DrawPlanar_ClearStructures(context);
326
free(pContext);
327
}
328
329
/********************************************************************
330
********************************************************************/
331
332
int _DrawPlanar_InitGraph(graphP theGraph, int N)
333
{
334
DrawPlanarContext *context = NULL;
335
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
336
337
if (context == NULL)
338
{
339
return NOTOK;
340
}
341
else
342
{
343
theGraph->N = N;
344
theGraph->edgeOffset = 2*N;
345
if (theGraph->arcCapacity == 0)
346
theGraph->arcCapacity = 2*DEFAULT_EDGE_LIMIT*N;
347
348
// Create custom structures, initialized at graph level,
349
// uninitialized at vertex and graph node levels.
350
if (_DrawPlanar_CreateStructures(context) != OK)
351
{
352
return NOTOK;
353
}
354
355
// This call initializes the base graph structures, but it also
356
// initializes the custom graphnode and vertex level structures
357
// due to the overloads of InitGraphNode and InitVertexRec
358
context->functions.fpInitGraph(theGraph, N);
359
}
360
361
return OK;
362
}
363
364
/********************************************************************
365
********************************************************************/
366
367
void _DrawPlanar_ReinitializeGraph(graphP theGraph)
368
{
369
DrawPlanarContext *context = NULL;
370
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
371
372
if (context != NULL)
373
{
374
// Reinitialization can go much faster if the underlying
375
// init graph node and vertex rec functions are called,
376
// rather than the overloads of this module, because it
377
// avoids lots of unnecessary gp_FindExtension() calls.
378
if (theGraph->functions.fpInitGraphNode == _DrawPlanar_InitGraphNode &&
379
theGraph->functions.fpInitVertexRec == _DrawPlanar_InitVertexRec)
380
{
381
// Restore the graph function pointers
382
theGraph->functions.fpInitGraphNode = context->functions.fpInitGraphNode;
383
theGraph->functions.fpInitVertexRec = context->functions.fpInitVertexRec;
384
385
// Reinitialize the graph
386
context->functions.fpReinitializeGraph(theGraph);
387
388
// Restore the function pointers that attach this feature
389
theGraph->functions.fpInitGraphNode = _DrawPlanar_InitGraphNode;
390
theGraph->functions.fpInitVertexRec = _DrawPlanar_InitVertexRec;
391
392
// Do the reinitialization that is specific to this module
393
// InitStructures does vertex and graphnode levels
394
_DrawPlanar_InitStructures(context);
395
// Initialization of any graph level data structures follows here
396
}
397
398
// If optimization is not possible, then just stick with what works.
399
// Reinitialize the graph-level structure (of which there are none)
400
// and then invoke the reinitialize function.
401
else
402
{
403
// No need to call _InitStructures(context) here because the underlying
404
// function fpReinitializeGraph() already does the vertex and graph node
405
// levels due to the overloads of fpInitGraphNode() and fpInitVertexRec().
406
context->functions.fpReinitializeGraph(theGraph);
407
// Graph level reintializations would follow here
408
}
409
}
410
}
411
412
/********************************************************************
413
The current implementation does not support an increase of arc
414
(edge record) capacity once the extension is attached to the graph
415
data structure. This is only due to not being necessary to support.
416
For now, it is easy to ensure the correct capacity before attaching
417
the extension, but support could be added later if there is some
418
reason to do so.
419
********************************************************************/
420
421
int _DrawPlanar_EnsureArcCapacity(graphP theGraph, int requiredArcCapacity)
422
{
423
return NOTOK;
424
}
425
426
/********************************************************************
427
********************************************************************/
428
429
int _DrawPlanar_SortVertices(graphP theGraph)
430
{
431
DrawPlanarContext *context = NULL;
432
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
433
434
if (context != NULL)
435
{
436
if (theGraph->embedFlags == EMBEDFLAGS_DRAWPLANAR)
437
{
438
int I;
439
DrawPlanar_GraphNodeP newG = NULL;
440
DrawPlanar_VertexRecP newV = NULL;
441
442
// Relabel the context data members that indicate vertices
443
for (I=0; I < theGraph->N; I++)
444
{
445
context->V[I].ancestor = theGraph->G[context->V[I].ancestor].v;
446
context->V[I].ancestorChild = theGraph->G[context->V[I].ancestorChild].v;
447
}
448
449
// Now we have to sort the first N positions of context G and V arrays
450
// For simplicity we do this out-of-place with extra arrays
451
if ((newG = (DrawPlanar_GraphNodeP) malloc(theGraph->N * sizeof(DrawPlanar_GraphNode))) == NULL)
452
{
453
return NOTOK;
454
}
455
456
if ((newV = (DrawPlanar_VertexRecP) malloc(theGraph->N * sizeof(DrawPlanar_VertexRec))) == NULL)
457
{
458
free(newG);
459
return NOTOK;
460
}
461
462
// Let X==G[I].v be the location where the I^{th} record goes
463
// Given newG and newV arrays, we want to move context G[I] to newG[X]
464
// Then copy newG into G and newV into V
465
for (I=0; I < theGraph->N; I++)
466
{
467
newG[theGraph->G[I].v] = context->G[I];
468
newV[theGraph->G[I].v] = context->V[I];
469
}
470
471
memcpy(context->G, newG, theGraph->N * sizeof(DrawPlanar_GraphNode));
472
memcpy(context->V, newV, theGraph->N * sizeof(DrawPlanar_VertexRec));
473
474
free(newG);
475
free(newV);
476
}
477
478
if (context->functions.fpSortVertices(theGraph) != OK)
479
return NOTOK;
480
481
return OK;
482
}
483
484
return NOTOK;
485
}
486
487
/********************************************************************
488
Returns OK for a successful merge, NOTOK on an internal failure,
489
or NONEMBEDDABLE if the merge is blocked
490
********************************************************************/
491
492
int _DrawPlanar_MergeBicomps(graphP theGraph, int I, int RootVertex, int W, int WPrevLink)
493
{
494
DrawPlanarContext *context = NULL;
495
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
496
497
if (context != NULL)
498
{
499
if (theGraph->embedFlags == EMBEDFLAGS_DRAWPLANAR)
500
{
501
_CollectDrawingData(context, RootVertex, W, WPrevLink);
502
}
503
504
return context->functions.fpMergeBicomps(theGraph, I, RootVertex, W, WPrevLink);
505
}
506
507
return NOTOK;
508
}
509
510
/********************************************************************
511
********************************************************************/
512
513
int _DrawPlanar_HandleInactiveVertex(graphP theGraph, int BicompRoot, int *pW, int *pWPrevLink)
514
{
515
DrawPlanarContext *context = NULL;
516
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
517
518
if (context != NULL)
519
{
520
int RetVal = context->functions.fpHandleInactiveVertex(theGraph, BicompRoot, pW, pWPrevLink);
521
522
if (theGraph->embedFlags == EMBEDFLAGS_DRAWPLANAR)
523
{
524
if (_BreakTie(context, BicompRoot, *pW, *pWPrevLink) != OK)
525
return NOTOK;
526
}
527
528
return RetVal;
529
}
530
531
return NOTOK;
532
}
533
534
/********************************************************************
535
********************************************************************/
536
537
void _DrawPlanar_InitGraphNode(graphP theGraph, int I)
538
{
539
DrawPlanarContext *context = NULL;
540
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
541
542
if (context != NULL)
543
{
544
context->functions.fpInitGraphNode(theGraph, I);
545
_InitDrawGraphNode(context, I);
546
}
547
}
548
549
/********************************************************************
550
********************************************************************/
551
552
void _InitDrawGraphNode(DrawPlanarContext *context, int I)
553
{
554
context->G[I].pos = 0;
555
context->G[I].start = 0;
556
context->G[I].end = 0;
557
}
558
559
/********************************************************************
560
********************************************************************/
561
562
void _DrawPlanar_InitVertexRec(graphP theGraph, int I)
563
{
564
DrawPlanarContext *context = NULL;
565
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
566
567
if (context != NULL)
568
{
569
context->functions.fpInitVertexRec(theGraph, I);
570
_InitDrawVertexRec(context, I);
571
}
572
}
573
574
/********************************************************************
575
********************************************************************/
576
577
void _InitDrawVertexRec(DrawPlanarContext *context, int I)
578
{
579
context->V[I].drawingFlag = DRAWINGFLAG_BEYOND;
580
context->V[I].ancestorChild = 0;
581
context->V[I].ancestor = 0;
582
context->V[I].tie[0] = context->V[I].tie[1] = NIL;
583
}
584
585
/********************************************************************
586
********************************************************************/
587
588
int _DrawPlanar_EmbedPostprocess(graphP theGraph, int I, int edgeEmbeddingResult)
589
{
590
DrawPlanarContext *context = NULL;
591
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
592
593
if (context != NULL)
594
{
595
int RetVal = context->functions.fpEmbedPostprocess(theGraph, I, edgeEmbeddingResult);
596
597
if (theGraph->embedFlags == EMBEDFLAGS_DRAWPLANAR)
598
{
599
if (RetVal == OK)
600
{
601
RetVal = _ComputeVisibilityRepresentation(context);
602
}
603
}
604
605
return RetVal;
606
}
607
608
return NOTOK;
609
}
610
611
/********************************************************************
612
********************************************************************/
613
614
int _DrawPlanar_CheckEmbeddingIntegrity(graphP theGraph, graphP origGraph)
615
{
616
DrawPlanarContext *context = NULL;
617
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
618
619
if (context != NULL)
620
{
621
if (context->functions.fpCheckEmbeddingIntegrity(theGraph, origGraph) != OK)
622
return NOTOK;
623
624
return _CheckVisibilityRepresentationIntegrity(context);
625
}
626
627
return NOTOK;
628
}
629
630
/********************************************************************
631
********************************************************************/
632
633
int _DrawPlanar_CheckObstructionIntegrity(graphP theGraph, graphP origGraph)
634
{
635
return OK;
636
}
637
638
/********************************************************************
639
********************************************************************/
640
641
int _DrawPlanar_ReadPostprocess(graphP theGraph, void *extraData, long extraDataSize)
642
{
643
DrawPlanarContext *context = NULL;
644
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
645
646
if (context != NULL)
647
{
648
if (context->functions.fpReadPostprocess(theGraph, extraData, extraDataSize) != OK)
649
return NOTOK;
650
651
else if (extraData != NULL && extraDataSize > 0)
652
{
653
int I, tempInt;
654
char line[64], tempChar;
655
656
sprintf(line, "<%s>", DRAWPLANAR_NAME);
657
658
// Find the start of the data for this feature
659
extraData = strstr(extraData, line);
660
if (extraData == NULL)
661
return NOTOK;
662
663
// Advance past the start tag
664
extraData = (void *) ((char *) extraData + strlen(line)+1);
665
666
// Read the N lines of vertex information
667
for (I = 0; I < theGraph->N; I++)
668
{
669
sscanf(extraData, " %d%c %d %d %d", &tempInt, &tempChar,
670
&context->G[I].pos,
671
&context->G[I].start,
672
&context->G[I].end);
673
674
extraData = strchr(extraData, '\n') + 1;
675
}
676
677
// Read the lines that contain edge information
678
for (I = theGraph->edgeOffset; I < theGraph->edgeOffset+2*theGraph->M; I++)
679
{
680
sscanf(extraData, " %d%c %d %d %d", &tempInt, &tempChar,
681
&context->G[I].pos,
682
&context->G[I].start,
683
&context->G[I].end);
684
685
extraData = strchr(extraData, '\n') + 1;
686
}
687
}
688
689
return OK;
690
}
691
692
return NOTOK;
693
}
694
695
/********************************************************************
696
********************************************************************/
697
698
int _DrawPlanar_WritePostprocess(graphP theGraph, void **pExtraData, long *pExtraDataSize)
699
{
700
DrawPlanarContext *context = NULL;
701
gp_FindExtension(theGraph, DRAWPLANAR_ID, (void *)&context);
702
703
if (context != NULL)
704
{
705
if (context->functions.fpWritePostprocess(theGraph, pExtraData, pExtraDataSize) != OK)
706
return NOTOK;
707
else
708
{
709
char line[64];
710
int maxLineSize = 64, extraDataPos = 0, I;
711
int GSize = theGraph->edgeOffset + theGraph->arcCapacity;
712
char *extraData = (char *) malloc((GSize + 2) * maxLineSize * sizeof(char));
713
714
if (extraData == NULL)
715
return NOTOK;
716
717
// Bit of an unlikely case, but for safety, a bigger maxLineSize
718
// and line array size are needed to handle very large graphs
719
if (theGraph->N > 2000000000)
720
{
721
free(extraData);
722
return NOTOK;
723
}
724
725
sprintf(line, "<%s>\n", DRAWPLANAR_NAME);
726
strcpy(extraData+extraDataPos, line);
727
extraDataPos += (int) strlen(line);
728
729
for (I = 0; I < theGraph->N; I++)
730
{
731
sprintf(line, "%d: %d %d %d\n", I,
732
context->G[I].pos,
733
context->G[I].start,
734
context->G[I].end);
735
strcpy(extraData+extraDataPos, line);
736
extraDataPos += (int) strlen(line);
737
}
738
739
for (I = theGraph->edgeOffset; I < theGraph->edgeOffset+2*theGraph->M; I++)
740
{
741
sprintf(line, "%d: %d %d %d\n", I,
742
context->G[I].pos,
743
context->G[I].start,
744
context->G[I].end);
745
strcpy(extraData+extraDataPos, line);
746
extraDataPos += (int) strlen(line);
747
}
748
749
sprintf(line, "</%s>\n", DRAWPLANAR_NAME);
750
strcpy(extraData+extraDataPos, line);
751
extraDataPos += (int) strlen(line);
752
753
*pExtraData = (void *) extraData;
754
*pExtraDataSize = extraDataPos * sizeof(char);
755
}
756
757
return OK;
758
}
759
760
return NOTOK;
761
}
762
763