Home | History | Annotate | Download | only in src
      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