1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41 
42 /* Hybrid linear-contour model reconstruction */
43 #include "_cvaux.h"
44 
45 #define CV_IMPL CV_EXTERN_C
46 
47 const float LCM_CONST_ZERO = 1e-6f;
48 
49 /****************************************************************************************\
50 *                                    Auxiliary struct definitions                                 *
51 \****************************************************************************************/
52 typedef struct CvLCM
53 {
54     CvGraph* Graph;
55     CvVoronoiDiagram2D* VoronoiDiagram;
56     CvMemStorage* ContourStorage;
57     CvMemStorage* EdgeStorage;
58     float maxWidth;
59 } CvLCM;
60 
61 typedef struct CvLCMComplexNodeData
62 {
63     CvVoronoiNode2D edge_node;
64     CvPoint2D32f site_first_pt;
65     CvPoint2D32f site_last_pt;
66     CvVoronoiSite2D* site_first;
67     CvVoronoiSite2D* site_last;
68     CvVoronoiEdge2D* edge;
69 } CvLCMComplexNodeData;
70 
71 typedef struct CvLCMData
72 {
73     CvVoronoiNode2D* pnode;
74     CvVoronoiSite2D* psite;
75     CvVoronoiEdge2D* pedge;
76 } CvLCMData;
77 
78 
79 /****************************************************************************************\
80 *                                    Function definitions                                *
81 \****************************************************************************************/
82 
83 #define _CV_READ_SEQ_ELEM( elem, reader, type )                       \
84 {                                                              \
85     assert( (reader).seq->elem_size == sizeof(*elem));         \
86     elem = (type)(reader).ptr;                                 \
87     CV_NEXT_SEQ_ELEM( sizeof(*elem), reader )                  \
88 }
89 
90 #define _CV_IS_SITE_REFLEX( SITE )  ((SITE) ->node[0] == (SITE) ->node[1])
91 #define _CV_IS_EDGE_REFLEX( EDGE )  (( (EDGE)->site[0]->node[0] == (EDGE)->site[0]->node[0] ) || \
92                                       ( (EDGE)->site[1]->node[0] == (EDGE)->site[1]->node[0] ) )
93 
94 #define _CV_INITIALIZE_CVLCMDATA(STRUCT,SITE,EDGE,NODE)\
95 { (STRUCT)->psite = SITE ; (STRUCT)->pedge = EDGE; (STRUCT)->pnode = NODE;}
96 /*F///////////////////////////////////////////////////////////////////////////////////////
97 //    Author:  Andrey Sobolev
98 //    Name:    _cvConstructLCM
99 //    Purpose: Function constructs hybrid model
100 //    Context:
101 //    Parameters:
102 //      LCM : in&out.
103 //    Returns: 1, if hybrid model was succesfully constructed
104 //             0, if some error occures
105 //F*/
106 CV_IMPL
107 int _cvConstructLCM(CvLCM* LCM);
108 
109 /*F///////////////////////////////////////////////////////////////////////////////////////
110 //    Author:  Andrey Sobolev
111 //    Name:    _cvConstructLCMComplexNode
112 //    Purpose: Function constructs Complex Node (node, which consists of
113 //             two points and more) of hybrid model
114 //    Context:
115 //    Parameters:
116 //      pLCM : in&out.
117 //      pLCMEdge: in, input edge of hybrid model
118 //      pLCMInputData: in, input parameters
119 //    Returns: pointer to constructed node
120 //F*/
121 CV_IMPL
122 CvLCMNode* _cvConstructLCMComplexNode(CvLCM* pLCM,
123                                       CvLCMEdge* pLCMEdge,
124                                       CvLCMData* pLCMInputData);
125 
126 /*F///////////////////////////////////////////////////////////////////////////////////////
127 //    Author:  Andrey Sobolev
128 //    Name:    _cvConstructLCMSimpleNode
129 //    Purpose: Function constructs Simple Node (node, which consists of
130 //             one point) of hybrid model
131 //    Context:
132 //    Parameters:
133 //      pLCM : in&out.
134 //      pLCMEdge: in, input edge of hybrid model
135 //      pLCMInputData: in, input parameters
136 //    Returns: pointer to constructed node
137 //F*/
138 CV_IMPL
139 CvLCMNode* _cvConstructLCMSimpleNode(CvLCM* pLCM,
140                                     CvLCMEdge* pLCMEdge,
141                                     CvLCMData* pLCMInputData);
142 
143 /*F///////////////////////////////////////////////////////////////////////////////////////
144 //    Author:  Andrey Sobolev
145 //    Name:    _cvConstructLCMSimpleNode
146 //    Purpose: Function constructs Edge of hybrid model
147 //    Context:
148 //    Parameters:
149 //      pLCM : in&out.
150 //      pLCMInputData: in, input parameters
151 //    Returns: pointer to constructed edge
152 //F*/
153 CV_IMPL
154 CvLCMEdge* _cvConstructLCMEdge(CvLCM* pLCM,
155                                CvLCMData* pLCMInputData);
156 
157 /*F///////////////////////////////////////////////////////////////////////////////////////
158 //    Author:  Andrey Sobolev
159 //    Name:    _cvTreatExeptionalCase
160 //    Purpose: Function treats triangles and regular polygons
161 //    Context:
162 //    Parameters:
163 //      pLCM : in, information about graph
164 //      pLCMInputData: in, input parameters
165 //    Returns: pointer to graph node
166 //F*/
167 CV_IMPL
168 CvLCMNode* _cvTreatExeptionalCase(CvLCM* pLCM,
169                                   CvLCMData* pLCMInputData);
170 
171 /*F///////////////////////////////////////////////////////////////////////////////////////
172 //    Author:  Andrey Sobolev
173 //    Name:    _cvNodeMultyplicity
174 //    Purpose: Function seeks all non-boundary edges incident to
175 //              given node and correspondent incident sites
176 //    Context:
177 //    Parameters:
178 //      pEdge : in, original edge
179 //      pNode : in, given node
180 //      LinkedEdges : out, matrix of incident edges
181 //      LinkedSites : out, matrix of incident sites
182 //      pSite: in, original site (pNode must be the begin point of pEdge
183 //              for this pSite, this property hold out far all edges)
184 //    Returns: number of incident edges (must be less than 10)
185 //F*/
186 CV_IMPL
187 int _cvNodeMultyplicity(CvVoronoiSite2D* pSite,
188                         CvVoronoiEdge2D* pEdge,
189                         CvVoronoiNode2D* pNode,
190                         CvVoronoiEdge2D** LinkedEdges,
191                         CvVoronoiSite2D** LinkedSites);
192 
193 /*F///////////////////////////////////////////////////////////////////////////////////////
194 //    Author:  Andrey Sobolev
195 //    Name:    _cvCreateLCMNode
196 //    Purpose: Function create graph node
197 //    Context:
198 //    Parameters:
199 //      pLCM : in, information about graph
200 //    Returns: pointer to graph node
201 //F*/
202 CV_IMPL
203 CvLCMNode* _cvCreateLCMNode(CvLCM* pLCM);
204 
205 /*F///////////////////////////////////////////////////////////////////////////////////////
206 //    Author:  Andrey Sobolev
207 //    Name:    _cvCreateLCMEdge
208 //    Purpose: Function create graph edge
209 //    Context:
210 //    Parameters:
211 //      pLCM : in, information about graph
212 //    Returns: pointer to graph edge
213 //F*/
214 CV_IMPL
215 CvLCMEdge* _cvCreateLCMEdge(CvLCM* pLCM);
216 
217 /*F///////////////////////////////////////////////////////////////////////////////////////
218 //    Author:  Andrey Sobolev
219 //    Name:    _cvCreateLCMNode
220 //    Purpose: Function establishs the connection between node and ege
221 //    Context:
222 //    Parameters:
223 //      LCMNode : in, graph node
224 //      LCMEdge : in, graph edge
225 //      LCMEdge_prev : in&out, previous edge, connected with given node
226 //      index: in,
227 //      i    : =0, if node is initial for edge
228 //             =1, if node  is terminal for edge
229 //    Returns:
230 //F*/
231 CV_IMPL
232 void _cvAttachLCMEdgeToLCMNode(CvLCMNode* LCMNode,
233                                CvLCMEdge* LCMEdge,
234                                CvLCMEdge* &LCMEdge_prev,
235                                int index,
236                                int i);
237 /*F///////////////////////////////////////////////////////////////////////////////////////
238 //    Author:  Andrey Sobolev
239 //    Name:    _cvProjectionPointToSegment
240 //    Purpose: Function computes the ortogonal projection of PointO to
241 //             to segment[PointA, PointB]
242 //    Context:
243 //    Parameters:
244 //      PointO, PointA,PointB: in, given points
245 //      PrPoint : out, projection
246 //      dist : distance from PointO to PrPoint
247 //    Returns:
248 //F*/
249 CV_IMPL
250 void _cvProjectionPointToSegment(CvPoint2D32f* PointO,
251                                  CvPoint2D32f* PointA,
252                                  CvPoint2D32f* PointB,
253                                  CvPoint2D32f* PrPoint,
254                                  float* dist);
255 
256 /*F///////////////////////////////////////////////////////////////////////////////////////
257 //    Author:  Andrey Sobolev
258 //    Name:    _cvPrepareData
259 //    Purpose: Function fills up the struct CvLCMComplexNodeData
260 //    Context:
261 //    Parameters:
262 //      pLCMData : in
263 //      pLCMCCNData : out
264 //    Returns:
265 //F*/
266 CV_IMPL
267 void _cvPrepareData(CvLCMComplexNodeData* pLCMCCNData,
268                     CvLCMData* pLCMData);
269 
270 /****************************************************************************************\
271 *                                    Function realization                               *
272 \****************************************************************************************/
273 
274 CV_IMPL CvGraph* cvLinearContorModelFromVoronoiDiagram(CvVoronoiDiagram2D* VoronoiDiagram,
275                                                        float maxWidth)
276 {
277     CvMemStorage* LCMstorage;
278     CvSet* SiteSet;
279     CvLCM LCM = {NULL, VoronoiDiagram,NULL,NULL,maxWidth};
280 
281     CV_FUNCNAME( "cvLinearContorModelFromVoronoiDiagram" );
282      __BEGIN__;
283 
284     if( !VoronoiDiagram )
285         CV_ERROR( CV_StsBadArg,"Voronoi Diagram is not defined" );
286     if( maxWidth < 0 )
287         CV_ERROR( CV_StsBadArg,"Treshold parameter must be non negative" );
288 
289     for(SiteSet = VoronoiDiagram->sites;
290         SiteSet != NULL;
291         SiteSet = (CvSet*)SiteSet->h_next)
292         {
293             if(SiteSet->v_next)
294                 CV_ERROR( CV_StsBadArg,"Can't operate with multiconnected domains" );
295             if(SiteSet->total > 70000)
296                 CV_ERROR( CV_StsBadArg,"Can't operate with large domains" );
297         }
298 
299 
300     LCMstorage = cvCreateMemStorage(0);
301     LCM.EdgeStorage = cvCreateChildMemStorage(LCMstorage);
302     LCM.ContourStorage = cvCreateChildMemStorage(LCMstorage);
303     LCM.Graph = cvCreateGraph(CV_SEQ_KIND_GRAPH|CV_GRAPH_FLAG_ORIENTED,
304                               sizeof(CvGraph),
305                               sizeof(CvLCMNode),
306                               sizeof(CvLCMEdge),
307                               LCMstorage);
308     if(!_cvConstructLCM(&LCM))
309         cvReleaseLinearContorModelStorage(&LCM.Graph);
310 
311 
312     __END__;
313     return LCM.Graph;
314 }//end of cvLinearContorModelFromVoronoiDiagram
315 
316 CV_IMPL int cvReleaseLinearContorModelStorage(CvGraph** Graph)
317 {
318     CvSeq* LCMNodeSeq, *LCMEdgeSeq;
319     CvLCMNode* pLCMNode;
320     CvLCMEdge* pLCMEdge;
321 
322     /*CV_FUNCNAME( "cvReleaseLinearContorModelStorage" );*/
323      __BEGIN__;
324 
325     if(!Graph || !(*Graph))
326         return 0;
327 
328     LCMNodeSeq = (CvSeq*)(*Graph);
329     LCMEdgeSeq = (CvSeq*)(*Graph)->edges;
330     if(LCMNodeSeq->total > 0)
331     {
332         pLCMNode = (CvLCMNode*)cvGetSeqElem(LCMNodeSeq,0);
333         if(pLCMNode->contour->storage)
334             cvReleaseMemStorage(&pLCMNode->contour->storage);
335     }
336     if(LCMEdgeSeq->total > 0)
337     {
338         pLCMEdge = (CvLCMEdge*)cvGetSeqElem(LCMEdgeSeq,0);
339         if(pLCMEdge->chain->storage)
340             cvReleaseMemStorage(&pLCMEdge->chain->storage);
341     }
342     if((*Graph)->storage)
343         cvReleaseMemStorage(&(*Graph)->storage);
344     *Graph = NULL;
345 
346 
347     __END__;
348     return 1;
349 }//end of cvReleaseLinearContorModelStorage
350 
351 int _cvConstructLCM(CvLCM* LCM)
352 {
353     CvVoronoiSite2D* pSite = 0;
354     CvVoronoiEdge2D* pEdge = 0, *pEdge1;
355     CvVoronoiNode2D* pNode, *pNode1;
356 
357     CvVoronoiEdge2D* LinkedEdges[10];
358     CvVoronoiSite2D* LinkedSites[10];
359 
360     CvSeqReader reader;
361     CvLCMData LCMdata;
362     int i;
363 
364     for(CvSet* SiteSet = LCM->VoronoiDiagram->sites;
365         SiteSet != NULL;
366         SiteSet = (CvSet*)SiteSet->h_next)
367     {
368         cvStartReadSeq((CvSeq*)SiteSet, &reader);
369         for(i = 0; i < SiteSet->total; i++)
370         {
371             _CV_READ_SEQ_ELEM(pSite,reader,CvVoronoiSite2D*);
372             if(pSite->node[0] == pSite->node[1])
373                 continue;
374             pEdge = CV_LAST_VORONOIEDGE2D(pSite);
375             pNode = CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite);
376             if(pNode->radius > LCM->maxWidth)
377                 goto PREPARECOMPLEXNODE;
378 
379             pEdge1 = CV_PREV_VORONOIEDGE2D(pEdge,pSite);
380             pNode1 = CV_VORONOIEDGE2D_BEGINNODE(pEdge1,pSite);
381             if(pNode1->radius > LCM->maxWidth)
382                 goto PREPARECOMPLEXNODE;
383             if(pNode1->radius == 0)
384                 continue;
385             if(_cvNodeMultyplicity(pSite, pEdge,pNode,LinkedEdges,LinkedSites) == 1)
386                 goto PREPARESIMPLENODE;
387         }
388 // treate triangle or regular polygon
389         _CV_INITIALIZE_CVLCMDATA(&LCMdata,pSite,pEdge,CV_VORONOIEDGE2D_ENDNODE(pEdge,pSite));
390         if(!_cvTreatExeptionalCase(LCM,&LCMdata))
391             return 0;
392         continue;
393 
394 PREPARECOMPLEXNODE:
395         _CV_INITIALIZE_CVLCMDATA(&LCMdata,pSite,pEdge,CV_VORONOIEDGE2D_ENDNODE(pEdge,pSite));
396         if(!_cvConstructLCMComplexNode(LCM,NULL,&LCMdata))
397             return 0;
398         continue;
399 
400 PREPARESIMPLENODE:
401         _CV_INITIALIZE_CVLCMDATA(&LCMdata,pSite,pEdge,CV_VORONOIEDGE2D_ENDNODE(pEdge,pSite));
402         if(!_cvConstructLCMSimpleNode(LCM,NULL,&LCMdata))
403             return 0;
404         continue;
405     }
406     return 1;
407 }//end of _cvConstructLCM
408 
409 CvLCMNode* _cvConstructLCMComplexNode(CvLCM* pLCM,
410                                       CvLCMEdge* pLCMEdge,
411                                       CvLCMData* pLCMInputData)
412 {
413     CvLCMNode* pLCMNode;
414     CvLCMEdge* pLCMEdge_prev = NULL;
415     CvSeqWriter writer;
416     CvVoronoiSite2D* pSite, *pSite_first, *pSite_last;
417     CvVoronoiEdge2D* pEdge, *pEdge_stop;
418     CvVoronoiNode2D* pNode0, *pNode1;
419     CvLCMData LCMOutputData;
420     CvLCMComplexNodeData LCMCCNData;
421     int index = 0;
422 
423     _cvPrepareData(&LCMCCNData,pLCMInputData);
424 
425     pLCMNode = _cvCreateLCMNode(pLCM);
426     _cvAttachLCMEdgeToLCMNode(pLCMNode,pLCMEdge,pLCMEdge_prev,1,1);
427     cvStartAppendToSeq((CvSeq*)pLCMNode->contour,&writer);
428     CV_WRITE_SEQ_ELEM(LCMCCNData.site_last_pt, writer);
429     index++;
430 
431     if(pLCMEdge)
432     {
433         CV_WRITE_SEQ_ELEM(LCMCCNData.edge_node.pt, writer );
434         CV_WRITE_SEQ_ELEM(LCMCCNData.site_first_pt, writer );
435         index+=2;
436     }
437 
438     pSite_first = LCMCCNData.site_first;
439     pSite_last = LCMCCNData.site_last;
440     pEdge = LCMCCNData.edge;
441 
442     for(pSite = pSite_first;
443         pSite != pSite_last;
444         pSite = CV_NEXT_VORONOISITE2D(pSite),
445         pEdge = CV_PREV_VORONOIEDGE2D(CV_LAST_VORONOIEDGE2D(pSite),pSite))
446     {
447         pEdge_stop = CV_FIRST_VORONOIEDGE2D(pSite);
448         for(;pEdge && pEdge != pEdge_stop;
449              pEdge = CV_PREV_VORONOIEDGE2D(pEdge,pSite))
450         {
451             pNode0 = CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite);
452             pNode1 = CV_VORONOIEDGE2D_ENDNODE(pEdge,pSite);
453             if(pNode0->radius <= pLCM->maxWidth && pNode1->radius <= pLCM->maxWidth)
454             {
455                 _CV_INITIALIZE_CVLCMDATA(&LCMOutputData,pSite,pEdge,pNode1);
456                 _cvPrepareData(&LCMCCNData,&LCMOutputData);
457                 CV_WRITE_SEQ_ELEM(LCMCCNData.site_first_pt, writer);
458                 CV_WRITE_SEQ_ELEM(LCMCCNData.edge_node.pt, writer );
459                 index+=2;
460                 pLCMEdge = _cvConstructLCMEdge(pLCM,&LCMOutputData);
461                 _cvAttachLCMEdgeToLCMNode(pLCMNode,pLCMEdge,pLCMEdge_prev,index - 1,0);
462                 CV_WRITE_SEQ_ELEM(LCMCCNData.site_last_pt, writer);
463                 index++;
464 
465                 pSite = CV_TWIN_VORONOISITE2D(pSite,pEdge);
466                 pEdge_stop = CV_FIRST_VORONOIEDGE2D(pSite);
467                 if(pSite == pSite_last)
468                     break;
469             }
470         }
471         if(pSite == pSite_last)
472             break;
473 
474         CV_WRITE_SEQ_ELEM(pSite->node[1]->pt, writer);
475         index++;
476     }
477 
478     if(pLCMEdge_prev)
479         pLCMEdge_prev->next[(pLCMEdge_prev == (CvLCMEdge*)pLCMNode->first)] = pLCMNode->first;
480     cvEndWriteSeq(&writer);
481     return pLCMNode;
482 }//end of _cvConstructLCMComplexNode
483 
484 CvLCMNode* _cvConstructLCMSimpleNode(CvLCM* pLCM,
485                                      CvLCMEdge* pLCMEdge,
486                                      CvLCMData* pLCMInputData)
487 {
488     CvVoronoiEdge2D* pEdge = pLCMInputData->pedge;
489     CvVoronoiSite2D* pSite = pLCMInputData->psite;
490     CvVoronoiNode2D* pNode = CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite);
491 
492     CvVoronoiEdge2D* LinkedEdges[10];
493     CvVoronoiSite2D* LinkedSites[10];
494     int multyplicity = _cvNodeMultyplicity(pSite,pEdge,pNode,LinkedEdges,LinkedSites);
495     if(multyplicity == 2)
496     {
497         pLCMInputData->pedge = LinkedEdges[1];
498         pLCMInputData->psite = CV_TWIN_VORONOISITE2D(LinkedSites[1],LinkedEdges[1]);
499         return NULL;
500     }
501 
502     CvLCMEdge* pLCMEdge_prev = NULL;
503     CvLCMNode* pLCMNode;
504     CvLCMData LCMOutputData;
505 
506     pLCMNode = _cvCreateLCMNode(pLCM);
507     cvSeqPush((CvSeq*)pLCMNode->contour,&pNode->pt);
508     _cvAttachLCMEdgeToLCMNode(pLCMNode,pLCMEdge,pLCMEdge_prev,0,1);
509 
510     for(int i = (int)(pLCMEdge != NULL);i < multyplicity; i++)
511     {
512         pEdge = LinkedEdges[i];
513         pSite = LinkedSites[i];
514         _CV_INITIALIZE_CVLCMDATA(&LCMOutputData,CV_TWIN_VORONOISITE2D(pSite,pEdge),pEdge,pNode);
515         pLCMEdge = _cvConstructLCMEdge(pLCM,&LCMOutputData);
516         _cvAttachLCMEdgeToLCMNode(pLCMNode,pLCMEdge,pLCMEdge_prev,0,0);
517     }
518     pLCMEdge_prev->next[(pLCMEdge_prev == (CvLCMEdge*)pLCMNode->first)] = pLCMNode->first;
519     return pLCMNode;
520 }//end of _cvConstructLCMSimpleNode
521 
522 CvLCMEdge* _cvConstructLCMEdge(CvLCM* pLCM,
523                                CvLCMData* pLCMInputData)
524 {
525     CvVoronoiEdge2D* pEdge = pLCMInputData->pedge;
526     CvVoronoiSite2D* pSite = pLCMInputData->psite;
527     float width = 0;
528 
529     CvLCMData LCMData;
530     CvVoronoiNode2D* pNode0,*pNode1;
531 
532     CvLCMEdge* pLCMEdge = _cvCreateLCMEdge(pLCM);
533 
534     CvSeqWriter writer;
535     cvStartAppendToSeq(pLCMEdge->chain,&writer );
536 
537     pNode0 = pNode1 = pLCMInputData->pnode;
538     CV_WRITE_SEQ_ELEM(pNode0->pt, writer);
539     width += pNode0->radius;
540 
541     for(int counter = 0;
542             counter < pLCM->VoronoiDiagram->edges->total;
543             counter++)
544     {
545         pNode1 = CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite);
546         if(pNode1->radius >= pLCM->maxWidth)
547             goto CREATECOMPLEXNODE;
548 
549         CV_WRITE_SEQ_ELEM(pNode1->pt,writer);
550         width += pNode1->radius;
551         _CV_INITIALIZE_CVLCMDATA(&LCMData,pSite,pEdge,pNode1);
552         if(_cvConstructLCMSimpleNode(pLCM,pLCMEdge,&LCMData))
553             goto LCMEDGEEXIT;
554 
555         pEdge = LCMData.pedge; pSite = LCMData.psite;
556         pNode0 = pNode1;
557     }
558     return NULL;
559 
560 CREATECOMPLEXNODE:
561     _CV_INITIALIZE_CVLCMDATA(&LCMData,pSite,pEdge,pNode0);
562     CV_WRITE_SEQ_ELEM(LCMData.pnode->pt,writer);
563     width += LCMData.pnode->radius;
564     _cvConstructLCMComplexNode(pLCM,pLCMEdge,&LCMData);
565 
566 LCMEDGEEXIT:
567     cvEndWriteSeq(&writer);
568     pLCMEdge->width = width/pLCMEdge->chain->total;
569     return pLCMEdge;
570 }//end of _cvConstructLCMEdge
571 
572 CvLCMNode* _cvTreatExeptionalCase(CvLCM* pLCM,
573                                   CvLCMData* pLCMInputData)
574 {
575     CvVoronoiEdge2D* pEdge = pLCMInputData->pedge;
576     CvVoronoiSite2D* pSite = pLCMInputData->psite;
577     CvVoronoiNode2D* pNode = CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite);
578     CvLCMNode* pLCMNode = _cvCreateLCMNode(pLCM);
579     cvSeqPush((CvSeq*)pLCMNode->contour,&pNode->pt);
580     return pLCMNode;
581 }//end of _cvConstructLCMEdge
582 
583 CV_INLINE
584 CvLCMNode* _cvCreateLCMNode(CvLCM* pLCM)
585 {
586     CvLCMNode* pLCMNode;
587     cvSetAdd((CvSet*)pLCM->Graph, NULL, (CvSetElem**)&pLCMNode );
588     pLCMNode->contour = (CvContour*)cvCreateSeq(0, sizeof(CvContour),
589                                                    sizeof(CvPoint2D32f),pLCM->ContourStorage);
590     pLCMNode->first = NULL;
591     return pLCMNode;
592 }//end of _cvCreateLCMNode
593 
594 CV_INLINE
595 CvLCMEdge* _cvCreateLCMEdge(CvLCM* pLCM)
596 {
597     CvLCMEdge* pLCMEdge;
598     cvSetAdd( (CvSet*)(pLCM->Graph->edges), 0, (CvSetElem**)&pLCMEdge );
599     pLCMEdge->chain = cvCreateSeq(0, sizeof(CvSeq),sizeof(CvPoint2D32f),pLCM->EdgeStorage);
600     pLCMEdge->next[0] = pLCMEdge->next[1] = NULL;
601     pLCMEdge->vtx[0] =  pLCMEdge->vtx[1] = NULL;
602     pLCMEdge->index1 =  pLCMEdge->index2 = -1;
603     return pLCMEdge;
604 }//end of _cvCreateLCMEdge
605 
606 CV_INLINE
607 void _cvAttachLCMEdgeToLCMNode(CvLCMNode* LCMNode,
608                                CvLCMEdge* LCMEdge,
609                                CvLCMEdge* &LCMEdge_prev,
610                                int index,
611                                int i)
612 {
613     if(!LCMEdge)
614         return;
615     if(i==0)
616         LCMEdge->index1 = index;
617     else
618         LCMEdge->index2 = index;
619 
620     LCMEdge->vtx[i] = (CvGraphVtx*)LCMNode;
621     if(!LCMEdge_prev)
622         LCMNode->first = (CvGraphEdge*)LCMEdge;
623     else
624 //      LCMEdge_prev->next[(LCMEdge_prev == (CvLCMEdge*)LCMNode->first)] = (CvGraphEdge*)LCMEdge;
625         LCMEdge_prev->next[(LCMEdge_prev->vtx[0] != (CvGraphVtx*)LCMNode)] = (CvGraphEdge*)LCMEdge;
626 
627     LCMEdge->next[i] = LCMNode->first;
628     LCMEdge_prev = LCMEdge;
629 }//end of _cvAttachLCMEdgeToLCMNode
630 
631 
632 int _cvNodeMultyplicity(CvVoronoiSite2D* pSite,
633                         CvVoronoiEdge2D* pEdge,
634                         CvVoronoiNode2D* pNode,
635                         CvVoronoiEdge2D** LinkedEdges,
636                         CvVoronoiSite2D** LinkedSites)
637 {
638     if(!pNode->radius)
639         return -1;
640     assert(pNode == CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite));
641 
642     int multyplicity = 0;
643     CvVoronoiEdge2D* pEdge_cur = pEdge;
644     do
645     {
646         if(pEdge_cur->node[0]->radius && pEdge_cur->node[1]->radius)
647         {
648             LinkedEdges[multyplicity] = pEdge_cur;
649             LinkedSites[multyplicity] = pSite;
650             multyplicity++;
651         }
652         pEdge_cur = CV_PREV_VORONOIEDGE2D(pEdge_cur,pSite);
653         pSite = CV_TWIN_VORONOISITE2D(pSite,pEdge_cur);
654     }while(pEdge_cur != pEdge);
655     return multyplicity;
656 }//end of _cvNodeMultyplicity
657 
658 
659 CV_INLINE
660 void _cvPrepareData(CvLCMComplexNodeData* pLCMCCNData,
661                     CvLCMData* pLCMData)
662 {
663     pLCMCCNData->site_first = pLCMData->psite;
664     pLCMCCNData->site_last = CV_TWIN_VORONOISITE2D(pLCMData->psite,pLCMData->pedge);
665     if(pLCMData->pedge == CV_LAST_VORONOIEDGE2D(pLCMData->psite))
666     {
667         pLCMCCNData->edge = CV_PREV_VORONOIEDGE2D(pLCMData->pedge,pLCMData->psite);
668         pLCMCCNData->edge_node = *pLCMData->pnode;
669         pLCMCCNData->site_first_pt = pLCMData->psite->node[0]->pt;
670         pLCMCCNData->site_last_pt = pLCMData->psite->node[0]->pt;
671     }
672     else
673     {
674         pLCMCCNData->edge = pLCMData->pedge;
675         pLCMCCNData->edge_node = *pLCMData->pnode;
676         _cvProjectionPointToSegment(&pLCMCCNData->edge_node.pt,
677                                   &pLCMCCNData->site_first->node[0]->pt,
678                                   &pLCMCCNData->site_first->node[1]->pt,
679                                   &pLCMCCNData->site_first_pt,
680                                   NULL);
681         _cvProjectionPointToSegment(&pLCMCCNData->edge_node.pt,
682                                   &pLCMCCNData->site_last->node[0]->pt,
683                                   &pLCMCCNData->site_last->node[1]->pt,
684                                   &pLCMCCNData->site_last_pt,
685                                   NULL);
686     }
687 }//end of _cvPrepareData
688 
689 
690 void _cvProjectionPointToSegment(CvPoint2D32f* PointO,
691                                  CvPoint2D32f* PointA,
692                                  CvPoint2D32f* PointB,
693                                  CvPoint2D32f* PrPoint,
694                                  float* dist)
695 {
696     float scal_AO_AB, scal_AB_AB;
697     CvPoint2D32f VectorAB = {PointB->x - PointA->x, PointB->y - PointA->y};
698     scal_AB_AB = VectorAB.x*VectorAB.x + VectorAB.y*VectorAB.y;
699     if(scal_AB_AB < LCM_CONST_ZERO)
700     {
701         *PrPoint = *PointA;
702         if(dist)
703             *dist = (float)sqrt( (double)(PointO->x -PointA->x)*(PointO->x -PointA->x) + (PointO->y - PointA->y)*(PointO->y - PointA->y));
704         return;
705     }
706 
707     CvPoint2D32f VectorAO = {PointO->x - PointA->x, PointO->y - PointA->y};
708     scal_AO_AB = VectorAO.x*VectorAB.x + VectorAO.y*VectorAB.y;
709 
710     if(dist)
711     {
712         float vector_AO_AB = (float)fabs(VectorAO.x*VectorAB.y - VectorAO.y*VectorAB.x);
713         *dist = (float)(vector_AO_AB/sqrt((double)scal_AB_AB));
714     }
715 
716     float alfa = scal_AO_AB/scal_AB_AB;
717     PrPoint->x = PointO->x - VectorAO.x + alfa*VectorAB.x;
718     PrPoint->y = PointO->y - VectorAO.y + alfa*VectorAB.y;
719     return;
720 }//end of _cvProjectionPointToSegment
721 
722 
723 
724 
725