| /*M/////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
| // |
| // By downloading, copying, installing or using the software you agree to this license. |
| // If you do not agree to this license, do not download, install, |
| // copy or use the software. |
| // |
| // |
| // Intel License Agreement |
| // For Open Source Computer Vision Library |
| // |
| // Copyright (C) 2000, Intel Corporation, all rights reserved. |
| // Third party copyrights are property of their respective owners. |
| // |
| // Redistribution and use in source and binary forms, with or without modification, |
| // are permitted provided that the following conditions are met: |
| // |
| // * Redistribution's of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // |
| // * Redistribution's in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // * The name of Intel Corporation may not be used to endorse or promote products |
| // derived from this software without specific prior written permission. |
| // |
| // This software is provided by the copyright holders and contributors "as is" and |
| // any express or implied warranties, including, but not limited to, the implied |
| // warranties of merchantability and fitness for a particular purpose are disclaimed. |
| // In no event shall the Intel Corporation or contributors be liable for any direct, |
| // indirect, incidental, special, exemplary, or consequential damages |
| // (including, but not limited to, procurement of substitute goods or services; |
| // loss of use, data, or profits; or business interruption) however caused |
| // and on any theory of liability, whether in contract, strict liability, |
| // or tort (including negligence or otherwise) arising in any way out of |
| // the use of this software, even if advised of the possibility of such damage. |
| // |
| //M*/ |
| |
| /* Reconstruction of contour skeleton */ |
| #include "_cvaux.h" |
| #include <time.h> |
| |
| #define NEXT_SEQ(seq,seq_first) ((seq) == (seq_first) ? seq->v_next : seq->h_next) |
| #define SIGN(x) ( x<0 ? -1:( x>0 ? 1:0 ) ) |
| |
| const float LEE_CONST_ZERO = 1e-6f; |
| const float LEE_CONST_DIFF_POINTS = 1e-2f; |
| const float LEE_CONST_ACCEPTABLE_ERROR = 1e-4f; |
| |
| /****************************************************************************************\ |
| * Auxiliary struct definitions * |
| \****************************************************************************************/ |
| |
| template<class T> |
| struct CvLeePoint |
| { |
| T x,y; |
| }; |
| |
| typedef CvLeePoint<float> CvPointFloat; |
| typedef CvLeePoint<float> CvDirection; |
| |
| struct CvVoronoiSiteInt; |
| struct CvVoronoiEdgeInt; |
| struct CvVoronoiNodeInt; |
| struct CvVoronoiParabolaInt; |
| struct CvVoronoiChainInt; |
| struct CvVoronoiHoleInt; |
| |
| struct CvVoronoiDiagramInt |
| { |
| CvSeq* SiteSeq; |
| CvSeq* EdgeSeq; |
| CvSeq* NodeSeq; |
| CvSeq* ChainSeq; |
| CvSeq* ParabolaSeq; |
| CvSeq* DirectionSeq; |
| CvSeq* HoleSeq; |
| CvVoronoiSiteInt* reflex_site; |
| CvVoronoiHoleInt* top_hole; |
| }; |
| |
| struct CvVoronoiStorageInt |
| { |
| CvMemStorage* SiteStorage; |
| CvMemStorage* EdgeStorage; |
| CvMemStorage* NodeStorage; |
| CvMemStorage* ChainStorage; |
| CvMemStorage* ParabolaStorage; |
| CvMemStorage* DirectionStorage; |
| CvMemStorage* HoleStorage; |
| }; |
| |
| struct CvVoronoiNodeInt |
| { |
| CvPointFloat node; |
| float radius; |
| }; |
| |
| struct CvVoronoiSiteInt |
| { |
| CvVoronoiNodeInt* node1; |
| CvVoronoiNodeInt* node2; |
| CvVoronoiEdgeInt* edge1; |
| CvVoronoiEdgeInt* edge2; |
| CvVoronoiSiteInt* next_site; |
| CvVoronoiSiteInt* prev_site; |
| CvDirection* direction; |
| }; |
| |
| struct CvVoronoiEdgeInt |
| { |
| CvVoronoiNodeInt* node1; |
| CvVoronoiNodeInt* node2; |
| CvVoronoiSiteInt* site; |
| CvVoronoiEdgeInt* next_edge; |
| CvVoronoiEdgeInt* prev_edge; |
| CvVoronoiEdgeInt* twin_edge; |
| CvVoronoiParabolaInt* parabola; |
| CvDirection* direction; |
| }; |
| |
| struct CvVoronoiParabolaInt |
| { |
| float map[6]; |
| float a; |
| CvVoronoiNodeInt* focus; |
| CvVoronoiSiteInt* directrice; |
| }; |
| |
| struct CvVoronoiChainInt |
| { |
| CvVoronoiSiteInt * first_site; |
| CvVoronoiSiteInt * last_site; |
| CvVoronoiChainInt* next_chain; |
| }; |
| |
| struct CvVoronoiHoleInt |
| { |
| CvSeq* SiteSeq; |
| CvSeq* ChainSeq; |
| CvVoronoiSiteInt* site_top; |
| CvVoronoiSiteInt* site_nearest; |
| CvVoronoiSiteInt* site_opposite; |
| CvVoronoiNodeInt* node; |
| CvVoronoiHoleInt* next_hole; |
| bool error; |
| float x_coord; |
| }; |
| |
| typedef CvVoronoiSiteInt* pCvVoronoiSite; |
| typedef CvVoronoiEdgeInt* pCvVoronoiEdge; |
| typedef CvVoronoiNodeInt* pCvVoronoiNode; |
| typedef CvVoronoiParabolaInt* pCvVoronoiParabola; |
| typedef CvVoronoiChainInt* pCvVoronoiChain; |
| typedef CvVoronoiHoleInt* pCvVoronoiHole; |
| typedef CvPointFloat* pCvPointFloat; |
| typedef CvDirection* pCvDirection; |
| |
| /****************************************************************************************\ |
| * Function definitions * |
| \****************************************************************************************/ |
| |
| /*F/////////////////////////////////////////////////////////////////////////////////////// |
| // Author: Andrey Sobolev |
| // Name: _cvLee |
| // Purpose: Compute Voronoi Diagram for one given polygon with holes |
| // Context: |
| // Parameters: |
| // ContourSeq : in, vertices of polygon. |
| // VoronoiDiagramInt : in&out, pointer to struct, which contains the |
| // description of Voronoi Diagram. |
| // VoronoiStorage: in, storage for Voronoi Diagram. |
| // contour_type: in, type of vertices. |
| // The possible values are CV_LEE_INT,CV_LEE_FLOAT,CV_LEE_DOUBLE. |
| // contour_orientation: in, orientation of polygons. |
| // = 1, if contour is left - oriented in left coordinat system |
| // =-1, if contour is left - oriented in right coordinat system |
| // attempt_number: in, number of unsuccessful attemts made by program to compute |
| // the Voronoi Diagram befor return the error |
| // |
| // Returns: 1, if Voronoi Diagram was succesfully computed |
| // 0, if some error occures |
| //F*/ |
| static int _cvLee(CvSeq* ContourSeq, |
| CvVoronoiDiagramInt* pVoronoiDiagramInt, |
| CvMemStorage* VoronoiStorage, |
| CvLeeParameters contour_type, |
| int contour_orientation, |
| int attempt_number); |
| |
| /*F/////////////////////////////////////////////////////////////////////////////////////// |
| // Author: Andrey Sobolev |
| // Name: _cvConstuctSites |
| // Purpose : Compute sites for given polygon with holes |
| // (site is an edge of polygon or a reflex vertex). |
| // Context: |
| // Parameters: |
| // ContourSeq : in, vertices of polygon |
| // pVoronoiDiagram : in, pointer to struct, which contains the |
| // description of Voronoi Diagram |
| // contour_type: in, type of vertices. The possible values are |
| // CV_LEE_INT,CV_LEE_FLOAT,CV_LEE_DOUBLE. |
| // contour_orientation: in, orientation of polygons. |
| // = 1, if contour is left - oriented in left coordinat system |
| // =-1, if contour is left - oriented in right coordinat system |
| // Return: 1, if sites were succesfully constructed |
| // 0, if some error occures |
| //F*/ |
| static int _cvConstuctSites(CvSeq* ContourSeq, |
| CvVoronoiDiagramInt* pVoronoiDiagram, |
| CvLeeParameters contour_type, |
| int contour_orientation); |
| |
| /*F/////////////////////////////////////////////////////////////////////////////////////// |
| // Author: Andrey Sobolev |
| // Name: _cvConstructChains |
| // Purpose : Compute chains for given polygon with holes. |
| // Context: |
| // Parameters: |
| // pVoronoiDiagram : in, pointer to struct, which contains the |
| // description of Voronoi Diagram |
| // Return: 1, if chains were succesfully constructed |
| // 0, if some error occures |
| //F*/ |
| static int _cvConstructChains(CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*F/////////////////////////////////////////////////////////////////////////////////////// |
| // Author: Andrey Sobolev |
| // Name: _cvConstructSkeleton |
| // Purpose: Compute skeleton for given collection of sites, using Lee algorithm |
| // Context: |
| // Parameters: |
| // VoronoiDiagram : in, pointer to struct, which contains the |
| // description of Voronoi Diagram. |
| // Returns: 1, if skeleton was succesfully computed |
| // 0, if some error occures |
| //F*/ |
| static int _cvConstructSkeleton(CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*F/////////////////////////////////////////////////////////////////////////////////////// |
| // Author: Andrey Sobolev |
| // Name: _cvConstructSiteTree |
| // Purpose: Construct tree of sites (by analogy with contour tree). |
| // Context: |
| // Parameters: |
| // VoronoiDiagram : in, pointer to struct, which contains the |
| // description of Voronoi Diagram. |
| // Returns: |
| //F*/ |
| static void _cvConstructSiteTree(CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*F/////////////////////////////////////////////////////////////////////////////////////// |
| // Author: Andrey Sobolev |
| // Name: _cvReleaseVoronoiStorage |
| // Purpose : Function realease storages. |
| // The storages are divided into two groups: |
| // SiteStorage, EdgeStorage, NodeStorage form the first group; |
| // ChainStorage,ParabolaStorage,DirectionStorage,HoleStorage form the second group. |
| // Context: |
| // Parameters: |
| // pVoronoiStorage: in, |
| // group1,group2: in, if group1<>0 then storages from first group released |
| // if group2<>0 then storages from second group released |
| // Return : |
| //F*/ |
| static void _cvReleaseVoronoiStorage(CvVoronoiStorageInt* pVoronoiStorage, int group1, int group2); |
| |
| /*F/////////////////////////////////////////////////////////////////////////////////////// |
| // Author: Andrey Sobolev |
| // Name: _cvConvert |
| // Purpose : Function convert internal representation of VD (via |
| // structs CvVoronoiSiteInt, CvVoronoiEdgeInt,CvVoronoiNodeInt) into |
| // external representation of VD (via structs CvVoronoiSite2D, CvVoronoiEdge2D, |
| // CvVoronoiNode2D) |
| // Context: |
| // Parameters: |
| // VoronoiDiagram: in |
| // VoronoiStorage: in |
| // change_orientation: in, if = -1 then the convertion is accompanied with change |
| // of orientation |
| // |
| // Return: 1, if convertion was succesfully completed |
| // 0, if some error occures |
| //F*/ |
| /* |
| static int _cvConvert(CvVoronoiDiagram2D* VoronoiDiagram, |
| CvMemStorage* VoronoiStorage, |
| int change_orientation); |
| */ |
| static int _cvConvert(CvVoronoiDiagram2D* VoronoiDiagram, |
| CvVoronoiDiagramInt VoronoiDiagramInt, |
| CvSet* &NewSiteSeqPrev, |
| CvSeqWriter &NodeWriter, |
| CvSeqWriter &EdgeWriter, |
| CvMemStorage* VoronoiStorage, |
| int change_orientation); |
| |
| /*F/////////////////////////////////////////////////////////////////////////////////////// |
| // Author: Andrey Sobolev |
| // Name: _cvConvertSameOrientation |
| // Purpose : Function convert internal representation of VD (via |
| // structs CvVoronoiSiteInt, CvVoronoiEdgeInt,CvVoronoiNodeInt) into |
| // external representation of VD (via structs CvVoronoiSite2D, CvVoronoiEdge2D, |
| // CvVoronoiNode2D) without change of orientation |
| // Context: |
| // Parameters: |
| // VoronoiDiagram: in |
| // VoronoiStorage: in |
| / |
| // Return: 1, if convertion was succesfully completed |
| // 0, if some error occures |
| //F*/ |
| /* |
| static int _cvConvertSameOrientation(CvVoronoiDiagram2D* VoronoiDiagram, |
| CvMemStorage* VoronoiStorage); |
| */ |
| static int _cvConvertSameOrientation(CvVoronoiDiagram2D* VoronoiDiagram, |
| CvVoronoiDiagramInt VoronoiDiagramInt, |
| CvSet* &NewSiteSeqPrev, |
| CvSeqWriter &NodeWriter, |
| CvSeqWriter &EdgeWriter, |
| CvMemStorage* VoronoiStorage); |
| |
| /*F/////////////////////////////////////////////////////////////////////////////////////// |
| // Author: Andrey Sobolev |
| // Name: _cvConvertChangeOrientation |
| // Purpose : Function convert internal representation of VD (via |
| // structs CvVoronoiSiteInt, CvVoronoiEdgeInt,CvVoronoiNodeInt) into |
| // external representation of VD (via structs CvVoronoiSite2D, CvVoronoiEdge2D, |
| // CvVoronoiNode2D) with change of orientation |
| // Context: |
| // Parameters: |
| // VoronoiDiagram: in |
| // VoronoiStorage: in |
| / |
| // Return: 1, if convertion was succesfully completed |
| // 0, if some error occures |
| //F*/ |
| /* |
| static int _cvConvertChangeOrientation(CvVoronoiDiagram2D* VoronoiDiagram, |
| CvMemStorage* VoronoiStorage); |
| */ |
| static int _cvConvertChangeOrientation(CvVoronoiDiagram2D* VoronoiDiagram, |
| CvVoronoiDiagramInt VoronoiDiagramInt, |
| CvSet* &NewSiteSeqPrev, |
| CvSeqWriter &NodeWriter, |
| CvSeqWriter &EdgeWriter, |
| CvMemStorage* VoronoiStorage); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute sites for external polygon. |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| ContourSeq : in, vertices of polygon |
| pReflexSite: out, pointer to reflex site,if any exist,else NULL |
| orientation: in, orientation of contour ( = 1 or = -1) |
| type: in, type of vertices. The possible values are (int)1, |
| (float)1,(double)1. |
| Return: 1, if sites were succesfully constructed |
| 0, if some error occures : |
| --------------------------------------------------------------------------*/ |
| template<class T> |
| int _cvConstructExtSites(CvVoronoiDiagramInt* pVoronoiDiagram, |
| CvSeq* ContourSeq, |
| int orientation, |
| T /*type*/); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute sites for internal polygon (for hole). |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| CurrSiteSeq: in, the sequence for sites to be constructed |
| CurrContourSeq : in, vertices of polygon |
| pTopSite: out, pointer to the most left site of polygon (it is the most left |
| vertex of polygon) |
| orientation: in, orientation of contour ( = 1 or = -1) |
| type: in, type of vertices. The possible values are (int)1, |
| (float)1,(double)1. |
| Return: 1, if sites were succesfully constructed |
| 0, if some error occures : |
| --------------------------------------------------------------------------*/ |
| template<class T> |
| int _cvConstructIntSites(CvVoronoiDiagramInt* pVoronoiDiagram, |
| CvSeq* CurrSiteSeq, |
| CvSeq* CurrContourSeq, |
| pCvVoronoiSite &pTopSite, |
| int orientation, |
| T /*type*/); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the simple chains of sites for external polygon. |
| Arguments |
| pVoronoiDiagram : in&out, pointer to struct, which contains the |
| description of Voronoi Diagram |
| |
| Return: 1, if chains were succesfully constructed |
| 0, if some error occures |
| --------------------------------------------------------------------------*/ |
| static int _cvConstructExtChains(CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the simple chains of sites for internal polygon (= hole) |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| CurrSiteSeq : in, the sequence of sites |
| CurrChainSeq : in,the sequence for chains to be constructed |
| pTopSite : in, the most left site of hole |
| |
| Return : |
| --------------------------------------------------------------------------*/ |
| static void _cvConstructIntChains(CvVoronoiDiagramInt* pVoronoiDiagram, |
| CvSeq* CurrChainSeq, |
| CvSeq* CurrSiteSeq, |
| pCvVoronoiSite pTopSite); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the initial Voronoi Diagram for single site |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pSite: in, pointer to site |
| |
| Return : |
| --------------------------------------------------------------------------*/ |
| static void _cvConstructEdges(pCvVoronoiSite pSite,CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function moves each node on small random value. The nodes are taken |
| from pVoronoiDiagram->NodeSeq. |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| begin,end: in, the first and the last nodes in pVoronoiDiagram->NodeSeq, |
| which moves |
| shift: in, the value of maximal shift. |
| Return : |
| --------------------------------------------------------------------------*/ |
| static void _cvRandomModification(CvVoronoiDiagramInt* pVoronoiDiagram, int begin, int end, float shift); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the internal Voronoi Diagram for external polygon. |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| Return : 1, if VD was constructed succesfully |
| 0, if some error occure |
| --------------------------------------------------------------------------*/ |
| static int _cvConstructExtVD(CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the external Voronoi Diagram for each internal polygon (hole). |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| Return : |
| --------------------------------------------------------------------------*/ |
| static void _cvConstructIntVD(CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function joins the Voronoi Diagrams of different |
| chains into one Voronoi Diagram |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pChain1,pChain1: in, given chains |
| Return : 1, if joining was succesful |
| 0, if some error occure |
| --------------------------------------------------------------------------*/ |
| static int _cvJoinChains(pCvVoronoiChain pChain1, |
| pCvVoronoiChain pChain2, |
| CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function finds the nearest site for top vertex |
| (= the most left vertex) of each hole |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| Return : |
| --------------------------------------------------------------------------*/ |
| static void _cvFindNearestSite(CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function seeks for site, which has common bisector in |
| final VD with top vertex of given hole. It stores in pHole->opposite_site. |
| The search begins from Hole->nearest_site and realizes in clockwise |
| direction around the top vertex of given hole. |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pHole : in, given hole |
| Return : 1, if the search was succesful |
| 0, if some error occure |
| --------------------------------------------------------------------------*/ |
| static int _cvFindOppositSiteCW(pCvVoronoiHole pHole, CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function seeks for site, which has common bisector in |
| final VD with top vertex of given hole. It stores in pHole->opposite_site. |
| The search begins from Hole->nearest_site and realizes in counterclockwise |
| direction around the top vertex of given hole. |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pHole : in, given hole |
| Return : 1, if the search was succesful |
| 0, if some error occure |
| --------------------------------------------------------------------------*/ |
| static int _cvFindOppositSiteCCW(pCvVoronoiHole pHole,CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function merges external VD of hole and internal VD, which was |
| constructed ealier. |
| Arguments |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pHole : in, given hole |
| Return : 1, if merging was succesful |
| 0, if some error occure |
| --------------------------------------------------------------------------*/ |
| static int _cvMergeVD(pCvVoronoiHole pHole,CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| |
| /* /////////////////////////////////////////////////////////////////////////////////////// |
| // Computation of bisectors // |
| /////////////////////////////////////////////////////////////////////////////////////// */ |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the bisector of two sites |
| Arguments |
| pSite_left,pSite_right: in, given sites |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pEdge : out, bisector |
| Return : |
| --------------------------------------------------------------------------*/ |
| void _cvCalcEdge(pCvVoronoiSite pSite_left, |
| pCvVoronoiSite pSite_right, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the bisector of point and site |
| Arguments |
| pSite : in, site |
| pNode : in, point |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pEdge : out, bisector |
| Return : |
| --------------------------------------------------------------------------*/ |
| void _cvCalcEdge(pCvVoronoiSite pSite, |
| pCvVoronoiNode pNode, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the bisector of point and site |
| Arguments |
| pSite : in, site |
| pNode : in, point |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pEdge : out, bisector |
| Return : |
| --------------------------------------------------------------------------*/ |
| void _cvCalcEdge(pCvVoronoiNode pNode, |
| pCvVoronoiSite pSite, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the direction of bisector of two segments |
| Arguments |
| pDirection1: in, direction of first segment |
| pDirection2: in, direction of second segment |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pEdge : out, bisector |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvCalcEdgeLL(pCvDirection pDirection1, |
| pCvDirection pDirection2, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the bisector of two points |
| Arguments |
| pPoint1, pPoint2: in, given points |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pEdge : out, bisector |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvCalcEdgePP(pCvPointFloat pPoint1, |
| pCvPointFloat pPoint2, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the bisector of segment and point. Since |
| it is parabola, it is defined by its focus (site - point) |
| and directrice(site-segment) |
| Arguments |
| pFocus : in, point, which defines the focus of parabola |
| pDirectrice: in, site - segment, which defines the directrice of parabola |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pEdge : out, bisector |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvCalcEdgePL(pCvVoronoiNode pFocus, |
| pCvVoronoiSite pDirectrice, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Compute the bisector of segment and point. Since |
| it is parabola, it is defined by its focus (site - point) |
| and directrice(site-segment) |
| Arguments |
| pFocus : in, point, which defines the focus of parabola |
| pDirectrice: in, site - segment, which defines the directrice of parabola |
| pVoronoiDiagram : in, pointer to struct, which contains the |
| description of Voronoi Diagram |
| pEdge : out, bisector |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvCalcEdgeLP(pCvVoronoiSite pDirectrice, |
| pCvVoronoiNode pFocus, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram); |
| |
| /* /////////////////////////////////////////////////////////////////////////////////////// |
| // Computation of intersections of bisectors // |
| /////////////////////////////////////////////////////////////////////////////////////// */ |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1,pEdge2: in, two edges |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvCalcEdgeIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| CvPointFloat* pPoint, |
| float &Radius); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1 : in, straight ray |
| pEdge2: in, straight ray or segment |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvLine_LineIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1 : in, straight ray |
| pEdge2: in, parabolic ray or segment |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvLine_ParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1 : in, straight ray |
| pEdge2: in, parabolic segment |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvLine_CloseParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1 : in, straight ray |
| pEdge2: in, parabolic ray |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvLine_OpenParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1 : in, parabolic ray |
| pEdge2: in, straight ray or segment |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvPar_LineIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius); |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1 : in, parabolic ray |
| pEdge2: in, straight ray |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvPar_OpenLineIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1 : in, parabolic ray |
| pEdge2: in, straight segment |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvPar_CloseLineIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1 : in, parabolic ray |
| pEdge2: in, parabolic ray or segment |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvPar_ParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius); |
| |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1 : in, parabolic ray |
| pEdge2: in, parabolic ray |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvPar_OpenParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes intersection of two edges. Intersection |
| must be the nearest to the marked point on pEdge1 |
| (this marked point is pEdge1->node1->node). |
| Arguments |
| pEdge1 : in, parabolic ray |
| pEdge2: in, parabolic segment |
| pPoint: out, intersection of pEdge1 and pEdge2 |
| Radius: out, distance between pPoint and sites, assosiated |
| with pEdge1 and pEdge2 (pPoint is situated on the equal |
| distance from site, assosiated with pEdge1 and from |
| site,assosiated with pEdge2) |
| Return : distance between pPoint and marked point on pEdge1 or |
| : -1, if edges have no intersections |
| --------------------------------------------------------------------------*/ |
| static |
| float _cvPar_CloseParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius); |
| |
| /* /////////////////////////////////////////////////////////////////////////////////////// |
| // Subsidiary functions // |
| /////////////////////////////////////////////////////////////////////////////////////// */ |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : |
| Arguments |
| pEdge1 : in |
| pEdge2 : out |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvMakeTwinEdge(pCvVoronoiEdge pEdge2, |
| pCvVoronoiEdge pEdge1); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : |
| Arguments |
| pEdge : in&out |
| pEdge_left_prev : in&out |
| pSite_left : in&out |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvStickEdgeLeftBegin(pCvVoronoiEdge pEdge, |
| pCvVoronoiEdge pEdge_left_prev, |
| pCvVoronoiSite pSite_left); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : |
| Arguments |
| pEdge : in&out |
| pEdge_right_next : in&out |
| pSite_right : in&out |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvStickEdgeRightBegin(pCvVoronoiEdge pEdge, |
| pCvVoronoiEdge pEdge_right_next, |
| pCvVoronoiSite pSite_right); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : |
| Arguments |
| pEdge : in&out |
| pEdge_left_next : in&out |
| pSite_left : in&out |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvStickEdgeLeftEnd(pCvVoronoiEdge pEdge, |
| pCvVoronoiEdge pEdge_left_next, |
| pCvVoronoiSite pSite_left); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : |
| Arguments |
| pEdge : in&out |
| pEdge_right_prev : in&out |
| pSite_right : in&out |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvStickEdgeRightEnd(pCvVoronoiEdge pEdge, |
| pCvVoronoiEdge pEdge_right_prev, |
| pCvVoronoiSite pSite_right); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : |
| Arguments |
| pEdge_left_cur : in |
| pEdge_left : in |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvTwinNULLLeft(pCvVoronoiEdge pEdge_left_cur, |
| pCvVoronoiEdge pEdge_left); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : |
| Arguments |
| pEdge_right_cur : in |
| pEdge_right : in |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvTwinNULLRight(pCvVoronoiEdge pEdge_right_cur, |
| pCvVoronoiEdge pEdge_right); |
| |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : function initializes the struct CvVoronoiNode |
| Arguments |
| pNode : out |
| pPoint : in, |
| radius : in |
| Return : |
| --------------------------------------------------------------------------*/ |
| template <class T> CV_INLINE |
| void _cvInitVoronoiNode(pCvVoronoiNode pNode, |
| T pPoint, float radius = 0); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : function initializes the struct CvVoronoiSite |
| Arguments |
| pSite : out |
| pNode1,pNode2,pPrev_site : in |
| Return : |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvInitVoronoiSite(pCvVoronoiSite pSite, |
| pCvVoronoiNode pNode1, |
| pCvVoronoiNode pNode2, |
| pCvVoronoiSite pPrev_site); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : function pushs the element in the end of the sequence |
| end returns its adress |
| Arguments |
| Seq : in, pointer to the sequence |
| Elem : in, element |
| Return : pointer to the element in the sequence |
| --------------------------------------------------------------------------*/ |
| template <class T> CV_INLINE |
| T _cvSeqPush(CvSeq* Seq, T pElem); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : function pushs the element in the begin of the sequence |
| end returns its adress |
| Arguments |
| Seq : in, pointer to the sequence |
| Elem : in, element |
| Return : pointer to the element in the sequence |
| --------------------------------------------------------------------------*/ |
| template <class T> CV_INLINE |
| T _cvSeqPushFront(CvSeq* Seq, T pElem); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : function pushs the element pHole in pHoleHierarchy->HoleSeq |
| so as all elements in this sequence would be normalized |
| according to field .x_coord of element. pHoleHierarchy->TopHole |
| points to hole with smallest x_coord. |
| Arguments |
| pHoleHierarchy : in, pointer to the structur |
| pHole : in, element |
| Return : pointer to the element in the sequence |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| void _cvSeqPushInOrder(CvVoronoiDiagramInt* pVoronoiDiagram, pCvVoronoiHole pHole); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : function intersects given edge pEdge (and his twin edge) |
| by point pNode on two parts |
| Arguments |
| pEdge : in, given edge |
| pNode : in, given point |
| EdgeSeq : in |
| Return : one of parts |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| pCvVoronoiEdge _cvDivideRightEdge(pCvVoronoiEdge pEdge, |
| pCvVoronoiNode pNode, |
| CvSeq* EdgeSeq); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : function intersects given edge pEdge (and his twin edge) |
| by point pNode on two parts |
| Arguments |
| pEdge : in, given edge |
| pNode : in, given point |
| EdgeSeq : in |
| Return : one of parts |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| pCvVoronoiEdge _cvDivideLeftEdge(pCvVoronoiEdge pEdge, |
| pCvVoronoiNode pNode, |
| CvSeq* EdgeSeq); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : function pushs the element in the end of the sequence |
| end returns its adress |
| Arguments |
| writer: in, writer associated with sequence |
| pElem : in, element |
| Return : pointer to the element in the sequence |
| --------------------------------------------------------------------------*/ |
| template<class T> CV_INLINE |
| T _cvWriteSeqElem(T pElem, CvSeqWriter &writer); |
| |
| /* /////////////////////////////////////////////////////////////////////////////////////// |
| // Mathematical functions // |
| /////////////////////////////////////////////////////////////////////////////////////// */ |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function changes x and y |
| Arguments |
| x,y : in&out |
| Return : |
| --------------------------------------------------------------------------*/ |
| template <class T> CV_INLINE |
| void _cvSwap(T &x, T &y); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes the inverse map to the |
| given ortogonal affine map |
| Arguments |
| A : in, given ortogonal affine map |
| B : out, inverse map |
| Return : 1, if inverse map exist |
| 0, else |
| --------------------------------------------------------------------------*/ |
| template <class T> CV_INLINE |
| int _cvCalcOrtogInverse(T* B, T* A); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes the composition of two affine maps |
| Arguments |
| A,B : in, given affine maps |
| Result: out, composition of A and B (Result = AB) |
| Return : |
| --------------------------------------------------------------------------*/ |
| template <class T> CV_INLINE |
| void _cvCalcComposition(T* Result,T* A,T* B); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes the image of point under |
| given affin map |
| Arguments |
| A : in, affine maps |
| pPoint : in, pointer to point |
| pImgPoint:out, pointer to image of point |
| Return : |
| --------------------------------------------------------------------------*/ |
| template<class T> CV_INLINE |
| void _cvCalcPointImage(pCvPointFloat pImgPoint,pCvPointFloat pPoint,T* A); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes the image of vector under |
| given affin map |
| Arguments |
| A : in, affine maps |
| pVector : in, pointer to vector |
| pImgVector:out, pointer to image of vector |
| Return : |
| --------------------------------------------------------------------------*/ |
| template<class T> CV_INLINE |
| void _cvCalcVectorImage(pCvDirection pImgVector,pCvDirection pVector,T* A); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes the distance between the point |
| and site. Internal function. |
| Arguments |
| pPoint : in, point |
| pSite : in, site |
| Return : distance |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| float _cvCalcDist(pCvPointFloat pPoint, pCvVoronoiSite pSite); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes the distance between two points |
| Arguments |
| pPoint1,pPoint2 : in, two points |
| Return : distance |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| float _cvPPDist(pCvPointFloat pPoint1,pCvPointFloat pPoint2); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function computes the distance betwin point and |
| segment. Internal function. |
| Arguments |
| pPoint: in, point |
| pPoint1,pPoint2 : in, segment [pPoint1,pPoint2] |
| Return : distance |
| --------------------------------------------------------------------------*/ |
| CV_INLINE |
| float _cvPLDist(pCvPointFloat pPoint,pCvPointFloat pPoint1,pCvDirection pDirection); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function solves the squar equation with real coefficients |
| T - float or double |
| Arguments |
| c2,c1,c0: in, real coefficients of polynom |
| X: out, array of roots |
| Return : number of roots |
| --------------------------------------------------------------------------*/ |
| template <class T> |
| int _cvSolveEqu2thR(T c2, T c1, T c0, T* X); |
| |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : Function solves the linear equation with real or complex coefficients |
| T - float or double or complex |
| Arguments |
| c1,c0: in, real or complex coefficients of polynom |
| X: out, array of roots |
| Return : number of roots |
| --------------------------------------------------------------------------*/ |
| template <class T> CV_INLINE |
| int _cvSolveEqu1th(T c1, T c0, T* X); |
| |
| /****************************************************************************************\ |
| * Storage Block Increase * |
| \****************************************************************************************/ |
| /*-------------------------------------------------------------------------- |
| Author : Andrey Sobolev |
| Description : For each sequence function creates the memory block sufficient to store |
| all elements of sequnce |
| Arguments |
| pVoronoiDiagramInt: in, pointer to struct, which contains the |
| description of Voronoi Diagram. |
| vertices_number: in, number of vertices in polygon |
| Return : |
| --------------------------------------------------------------------------*/ |
| void _cvSetSeqBlockSize(CvVoronoiDiagramInt* pVoronoiDiagramInt,int vertices_number) |
| { |
| int N = 2*vertices_number; |
| cvSetSeqBlockSize(pVoronoiDiagramInt->SiteSeq,N*pVoronoiDiagramInt->SiteSeq->elem_size); |
| cvSetSeqBlockSize(pVoronoiDiagramInt->EdgeSeq,3*N*pVoronoiDiagramInt->EdgeSeq->elem_size); |
| cvSetSeqBlockSize(pVoronoiDiagramInt->NodeSeq,5*N*pVoronoiDiagramInt->NodeSeq->elem_size); |
| cvSetSeqBlockSize(pVoronoiDiagramInt->ParabolaSeq,N*pVoronoiDiagramInt->ParabolaSeq->elem_size); |
| cvSetSeqBlockSize(pVoronoiDiagramInt->DirectionSeq,3*N*pVoronoiDiagramInt->DirectionSeq->elem_size); |
| cvSetSeqBlockSize(pVoronoiDiagramInt->ChainSeq,N*pVoronoiDiagramInt->DirectionSeq->elem_size); |
| cvSetSeqBlockSize(pVoronoiDiagramInt->HoleSeq,100*pVoronoiDiagramInt->HoleSeq->elem_size); |
| } |
| |
| /****************************************************************************************\ |
| * Function realization * |
| \****************************************************************************************/ |
| |
| |
| CV_IMPL int cvVoronoiDiagramFromContour(CvSeq* ContourSeq, |
| CvVoronoiDiagram2D** VoronoiDiagram, |
| CvMemStorage* VoronoiStorage, |
| CvLeeParameters contour_type, |
| int contour_orientation, |
| int attempt_number) |
| { |
| CV_FUNCNAME( "cvVoronoiDiagramFromContour" ); |
| |
| __BEGIN__; |
| |
| CvSet* SiteSeq = NULL; |
| CvSeq* CurContourSeq = NULL; |
| CvVoronoiDiagramInt VoronoiDiagramInt; |
| CvSeqWriter NodeWriter, EdgeWriter; |
| CvMemStorage* storage; |
| |
| memset( &VoronoiDiagramInt, 0, sizeof(VoronoiDiagramInt) ); |
| |
| if( !ContourSeq ) |
| CV_ERROR( CV_StsBadArg,"Contour sequence is empty" ); |
| |
| if(!VoronoiStorage) |
| CV_ERROR( CV_StsBadArg,"Storage is not initialized" ); |
| |
| if( contour_type < 0 || contour_type > 2) |
| CV_ERROR( CV_StsBadArg,"Unsupported parameter: type" ); |
| |
| if( contour_orientation != 1 && contour_orientation != -1) |
| CV_ERROR( CV_StsBadArg,"Unsupported parameter: orientation" ); |
| |
| storage = cvCreateChildMemStorage(VoronoiStorage); |
| (*VoronoiDiagram) = (CvVoronoiDiagram2D*)cvCreateSet(0,sizeof(CvVoronoiDiagram2D),sizeof(CvVoronoiNode2D), storage); |
| storage = cvCreateChildMemStorage(VoronoiStorage); |
| (*VoronoiDiagram)->edges = cvCreateSet(0,sizeof(CvSet),sizeof(CvVoronoiEdge2D), storage); |
| cvStartAppendToSeq((CvSeq*)(*VoronoiDiagram)->edges, &EdgeWriter); |
| cvStartAppendToSeq((CvSeq*)(*VoronoiDiagram), &NodeWriter); |
| |
| for(CurContourSeq = ContourSeq;\ |
| CurContourSeq != NULL;\ |
| CurContourSeq = CurContourSeq->h_next) |
| { |
| if(_cvLee(CurContourSeq, &VoronoiDiagramInt,VoronoiStorage,contour_type,contour_orientation,attempt_number)) |
| |
| { |
| if(!_cvConvert(*VoronoiDiagram,VoronoiDiagramInt,SiteSeq,NodeWriter,EdgeWriter,VoronoiStorage,contour_orientation)) |
| goto exit; |
| } |
| else if(CurContourSeq->total >= 3) |
| goto exit; |
| } |
| |
| cvEndWriteSeq(&EdgeWriter); |
| cvEndWriteSeq(&NodeWriter); |
| if(SiteSeq != NULL) |
| return 1; |
| |
| |
| __END__; |
| return 0; |
| }//end of cvVoronoiDiagramFromContour |
| |
| CV_IMPL int cvVoronoiDiagramFromImage(IplImage* pImage, |
| CvSeq** ContourSeq, |
| CvVoronoiDiagram2D** VoronoiDiagram, |
| CvMemStorage* VoronoiStorage, |
| CvLeeParameters regularization_method, |
| float approx_precision) |
| { |
| CV_FUNCNAME( "cvVoronoiDiagramFromContour" ); |
| int RESULT = 0; |
| |
| __BEGIN__; |
| |
| IplImage* pWorkImage = NULL; |
| CvSize image_size; |
| int i, multiplicator = 3; |
| |
| int approx_method; |
| CvMemStorage* ApproxContourStorage = NULL; |
| CvSeq* ApproxContourSeq = NULL; |
| |
| if( !ContourSeq ) |
| CV_ERROR( CV_StsBadArg,"Contour sequence is not initialized" ); |
| |
| if( (*ContourSeq)->total != 0) |
| CV_ERROR( CV_StsBadArg,"Contour sequence is not empty" ); |
| |
| if(!VoronoiStorage) |
| CV_ERROR( CV_StsBadArg,"Storage is not initialized" ); |
| |
| if(!pImage) |
| CV_ERROR( CV_StsBadArg,"Image is not initialized" ); |
| |
| if(pImage->nChannels != 1 || pImage->depth != 8) |
| CV_ERROR( CV_StsBadArg,"Unsupported image format" ); |
| |
| if(approx_precision<0 && approx_precision != CV_LEE_AUTO) |
| CV_ERROR( CV_StsBadArg,"Unsupported presision value" ); |
| |
| switch(regularization_method) |
| { |
| case CV_LEE_ERODE: image_size.width = pImage->width; |
| image_size.height = pImage->height; |
| pWorkImage = cvCreateImage(image_size,8,1); |
| cvErode(pImage,pWorkImage,0,1); |
| approx_method = CV_CHAIN_APPROX_TC89_L1; |
| break; |
| case CV_LEE_ZOOM: image_size.width = multiplicator*pImage->width; |
| image_size.height = multiplicator*pImage->height; |
| pWorkImage = cvCreateImage(image_size,8,1); |
| cvResize(pImage, pWorkImage, CV_INTER_NN); |
| approx_method = CV_CHAIN_APPROX_TC89_L1; |
| break; |
| case CV_LEE_NON: pWorkImage = pImage; |
| approx_method = CV_CHAIN_APPROX_TC89_L1; |
| break; |
| default: CV_ERROR( CV_StsBadArg,"Unsupported regularisation method" ); |
| break; |
| |
| } |
| |
| cvFindContours(pWorkImage, (*ContourSeq)->storage, ContourSeq, \ |
| sizeof(CvContour), CV_RETR_CCOMP, approx_method ); |
| |
| if(pWorkImage && pWorkImage != pImage ) |
| cvReleaseImage(&pWorkImage); |
| |
| ApproxContourStorage = cvCreateMemStorage(0); |
| if(approx_precision > 0) |
| { |
| ApproxContourSeq = cvApproxPoly(*ContourSeq, sizeof(CvContour), ApproxContourStorage,\ |
| CV_POLY_APPROX_DP,approx_precision,1); |
| |
| RESULT = cvVoronoiDiagramFromContour(ApproxContourSeq,VoronoiDiagram,VoronoiStorage,CV_LEE_INT,-1,10); |
| } |
| else if(approx_precision == CV_LEE_AUTO) |
| { |
| ApproxContourSeq = *ContourSeq; |
| for(i = 1; i < 50; i++) |
| { |
| RESULT = cvVoronoiDiagramFromContour(ApproxContourSeq,VoronoiDiagram,VoronoiStorage,CV_LEE_INT,-1,1); |
| if(RESULT) |
| break; |
| ApproxContourSeq = cvApproxPoly(ApproxContourSeq, sizeof(CvContour),ApproxContourStorage,\ |
| CV_POLY_APPROX_DP,(float)i,1); |
| } |
| } |
| else |
| RESULT = cvVoronoiDiagramFromContour(*ContourSeq,VoronoiDiagram,VoronoiStorage,CV_LEE_INT,-1,10); |
| /* |
| if(ApproxContourSeq) |
| { |
| cvClearMemStorage( (*ContourSeq)->storage ); |
| *ContourSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvPoint),(*ContourSeq)->storage); |
| CvSeqReader reader; |
| CvSeqWriter writer; |
| CvPoint Point; |
| cvStartAppendToSeq(*ContourSeq, &writer); |
| cvStartReadSeq(ApproxContourSeq, &reader); |
| for(int i = 0;i < ApproxContourSeq->total;i++) |
| { |
| CV_READ_SEQ_ELEM(Point,reader); |
| Point.y = 600 - Point.y; |
| CV_WRITE_SEQ_ELEM(Point,writer); |
| } |
| cvEndWriteSeq(&writer); |
| } |
| */ |
| |
| cvReleaseMemStorage(&ApproxContourStorage); |
| |
| |
| __END__; |
| return RESULT; |
| }//end of cvVoronoiDiagramFromImage |
| |
| CV_IMPL void cvReleaseVoronoiStorage(CvVoronoiDiagram2D* VoronoiDiagram, |
| CvMemStorage** pVoronoiStorage) |
| { |
| /*CV_FUNCNAME( "cvReleaseVoronoiStorage" );*/ |
| __BEGIN__; |
| |
| CvSeq* Seq; |
| |
| if(VoronoiDiagram->storage) |
| cvReleaseMemStorage(&VoronoiDiagram->storage); |
| for(Seq = (CvSeq*)VoronoiDiagram->sites; Seq != NULL; Seq = Seq->h_next) |
| if(Seq->storage) |
| cvReleaseMemStorage(&Seq->storage); |
| for(Seq = (CvSeq*)VoronoiDiagram->edges; Seq != NULL; Seq = Seq->h_next) |
| if(Seq->storage) |
| cvReleaseMemStorage(&Seq->storage); |
| |
| if(*pVoronoiStorage) |
| cvReleaseMemStorage(pVoronoiStorage); |
| |
| __END__; |
| }//end of cvReleaseVoronoiStorage |
| |
| static int _cvLee(CvSeq* ContourSeq, |
| CvVoronoiDiagramInt* pVoronoiDiagramInt, |
| CvMemStorage* VoronoiStorage, |
| CvLeeParameters contour_type, |
| int contour_orientation, |
| int attempt_number) |
| { |
| //orientation = 1 for left coordinat system |
| //orientation = -1 for right coordinat system |
| if(ContourSeq->total<3) |
| return 0; |
| |
| int attempt = 0; |
| CvVoronoiStorageInt VoronoiStorageInt; |
| |
| srand((int)time(NULL)); |
| |
| NEXTATTEMPT: |
| VoronoiStorageInt.SiteStorage = cvCreateChildMemStorage(VoronoiStorage); |
| VoronoiStorageInt.NodeStorage = cvCreateChildMemStorage(VoronoiStorage); |
| VoronoiStorageInt.EdgeStorage = cvCreateChildMemStorage(VoronoiStorage); |
| VoronoiStorageInt.ParabolaStorage = cvCreateMemStorage(0); |
| VoronoiStorageInt.ChainStorage = cvCreateMemStorage(0); |
| VoronoiStorageInt.DirectionStorage = cvCreateMemStorage(0); |
| VoronoiStorageInt.HoleStorage = cvCreateMemStorage(0); |
| |
| pVoronoiDiagramInt->SiteSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiSiteInt),VoronoiStorageInt.SiteStorage); |
| pVoronoiDiagramInt->NodeSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiNodeInt),VoronoiStorageInt.NodeStorage); |
| pVoronoiDiagramInt->EdgeSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiEdgeInt),VoronoiStorageInt.EdgeStorage); |
| pVoronoiDiagramInt->ChainSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiChainInt),VoronoiStorageInt.ChainStorage); |
| pVoronoiDiagramInt->DirectionSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvDirection),VoronoiStorageInt.DirectionStorage); |
| pVoronoiDiagramInt->ParabolaSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiParabolaInt),VoronoiStorageInt.ParabolaStorage); |
| pVoronoiDiagramInt->HoleSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiHoleInt),VoronoiStorageInt.HoleStorage); |
| |
| _cvSetSeqBlockSize(pVoronoiDiagramInt,ContourSeq->total); |
| |
| if(!_cvConstuctSites(ContourSeq, pVoronoiDiagramInt, contour_type,contour_orientation)) |
| { |
| attempt = attempt_number; |
| goto FAULT; |
| } |
| _cvRandomModification(pVoronoiDiagramInt, 0,pVoronoiDiagramInt->NodeSeq->total,0.2f); |
| |
| if(!_cvConstructChains(pVoronoiDiagramInt)) |
| { |
| attempt = attempt_number; |
| goto FAULT; |
| } |
| |
| if(!_cvConstructSkeleton(pVoronoiDiagramInt)) |
| goto FAULT; |
| |
| _cvConstructSiteTree(pVoronoiDiagramInt); |
| |
| //SUCCESS: |
| _cvReleaseVoronoiStorage(&VoronoiStorageInt,0,1); |
| return 1; |
| |
| FAULT: |
| _cvReleaseVoronoiStorage(&VoronoiStorageInt,1,1); |
| if(++attempt < attempt_number) |
| goto NEXTATTEMPT; |
| |
| return 0; |
| }// end of _cvLee |
| |
| static int _cvConstuctSites(CvSeq* ContourSeq, |
| CvVoronoiDiagramInt* pVoronoiDiagram, |
| CvLeeParameters contour_type, |
| int contour_orientation) |
| { |
| pVoronoiDiagram->reflex_site = NULL; |
| pVoronoiDiagram->top_hole = NULL; |
| int result = 0; |
| |
| switch(contour_type) |
| { |
| case CV_LEE_INT : result = _cvConstructExtSites(pVoronoiDiagram,ContourSeq,contour_orientation,(int)1); |
| break; |
| case CV_LEE_FLOAT : result = _cvConstructExtSites(pVoronoiDiagram,ContourSeq,contour_orientation,(float)1); |
| break; |
| case CV_LEE_DOUBLE : result = _cvConstructExtSites(pVoronoiDiagram,ContourSeq,contour_orientation,(double)1); |
| break; |
| default: return 0; |
| } |
| |
| if(!result) |
| return 0; |
| |
| CvSeq* CurSiteSeq; |
| CvVoronoiHoleInt Hole = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,0}; |
| pCvVoronoiSite pTopSite = 0; |
| for(CvSeq* CurContourSeq = ContourSeq->v_next;\ |
| CurContourSeq != NULL;\ |
| CurContourSeq = CurContourSeq->h_next) |
| { |
| if(CurContourSeq->total == 0) |
| continue; |
| |
| CurSiteSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiSiteInt),pVoronoiDiagram->SiteSeq->storage); |
| switch(contour_type) |
| { |
| case CV_LEE_INT : result = _cvConstructIntSites(pVoronoiDiagram,CurSiteSeq,CurContourSeq,pTopSite,contour_orientation,(int)1); |
| break; |
| case CV_LEE_FLOAT : result = _cvConstructIntSites(pVoronoiDiagram,CurSiteSeq,CurContourSeq,pTopSite,contour_orientation,(float)1); |
| break; |
| case CV_LEE_DOUBLE :result = _cvConstructIntSites(pVoronoiDiagram,CurSiteSeq,CurContourSeq,pTopSite,contour_orientation,(double)1); |
| break; |
| default: result = 0; |
| } |
| if(!result) |
| continue; |
| |
| Hole.SiteSeq = CurSiteSeq; |
| Hole.site_top = pTopSite; |
| Hole.x_coord = pTopSite->node1->node.x; |
| Hole.error = false; |
| _cvSeqPushInOrder(pVoronoiDiagram, &Hole); |
| } |
| return 1; |
| }//end of _cvConstuctSites |
| |
| static int _cvConstructChains(CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| if(!_cvConstructExtChains(pVoronoiDiagram)) |
| return 0; |
| |
| CvSeq* CurrChainSeq; |
| for(pCvVoronoiHole pHole = pVoronoiDiagram->top_hole;\ |
| pHole != NULL; \ |
| pHole = pHole->next_hole) |
| { |
| pHole->error = false; |
| CurrChainSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiChainInt),pVoronoiDiagram->ChainSeq->storage); |
| _cvConstructIntChains(pVoronoiDiagram,CurrChainSeq,pHole->SiteSeq,pHole->site_top); |
| pHole->ChainSeq = CurrChainSeq; |
| } |
| return 1; |
| }//end of _cvConstructChains |
| |
| static int _cvConstructSkeleton(CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| if(!_cvConstructExtVD(pVoronoiDiagram)) |
| return 0; |
| _cvConstructIntVD(pVoronoiDiagram); |
| _cvFindNearestSite(pVoronoiDiagram); |
| |
| float dx,dy; |
| int result; |
| for(pCvVoronoiHole pHole = pVoronoiDiagram->top_hole;\ |
| pHole != NULL; pHole = pHole->next_hole) |
| { |
| if(pHole->error) |
| continue; |
| dx = pHole->node->node.x - pHole->site_top->node1->node.x; |
| dy = pHole->node->node.y - pHole->site_top->node1->node.y; |
| |
| if(fabs(dy) < 0.01 && dx < 0) |
| pHole->site_opposite = pHole->site_nearest; |
| else |
| { |
| if(dy > 0) |
| result = _cvFindOppositSiteCCW(pHole,pVoronoiDiagram); |
| else |
| result = _cvFindOppositSiteCW(pHole,pVoronoiDiagram); |
| |
| if(!result) |
| { |
| pHole->error = true; |
| continue; |
| } |
| } |
| |
| if(!_cvMergeVD(pHole,pVoronoiDiagram)) |
| return 0; |
| } |
| return 1; |
| }//end of _cvConstructSkeleton |
| |
| static void _cvConstructSiteTree(CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| CvSeq* CurSeq = pVoronoiDiagram->SiteSeq; |
| for(pCvVoronoiHole pHole = pVoronoiDiagram->top_hole;\ |
| pHole != NULL; pHole = pHole->next_hole) |
| { |
| if(pHole->error) |
| continue; |
| if(CurSeq == pVoronoiDiagram->SiteSeq) |
| { |
| CurSeq->v_next = pHole->SiteSeq; |
| pHole->SiteSeq->v_prev = CurSeq; |
| } |
| else |
| { |
| CurSeq->h_next = pHole->SiteSeq; |
| pHole->SiteSeq->h_prev = CurSeq; |
| pHole->SiteSeq->v_prev = pVoronoiDiagram->SiteSeq; |
| } |
| CurSeq = pHole->SiteSeq; |
| } |
| CurSeq->h_next = NULL; |
| }//end of _cvConstructSiteTree |
| |
| static void _cvRandomModification(CvVoronoiDiagramInt* pVoronoiDiagram, int begin, int end, float shift) |
| { |
| CvSeqReader Reader; |
| pCvVoronoiNode pNode; |
| const float rnd_const = shift/RAND_MAX; |
| int i; |
| |
| cvStartReadSeq(pVoronoiDiagram->NodeSeq, &Reader,0); |
| for( i = begin; i < end; i++) |
| { |
| pNode = (pCvVoronoiNode)Reader.ptr; |
| pNode->node.x = (float)cvFloor(pNode->node.x) + rand()*rnd_const; |
| pNode->node.y = (float)cvFloor(pNode->node.y) + rand()*rnd_const; |
| CV_NEXT_SEQ_ELEM( sizeof(CvVoronoiNodeInt), Reader ); |
| } |
| |
| for(pCvVoronoiHole pHole = pVoronoiDiagram->top_hole;\ |
| pHole != NULL;\ |
| pHole = pHole->next_hole) |
| { |
| pHole->site_top->node1->node.x = (float)cvFloor(pHole->site_top->node1->node.x); |
| } |
| |
| }//end of _cvRandomModification |
| |
| static void _cvReleaseVoronoiStorage(CvVoronoiStorageInt* pVoronoiStorage, int group1, int group2) |
| { |
| //if group1 = 1 then SiteSeq, NodeSeq, EdgeSeq released |
| //if group2 = 1 then DirectionSeq, ParabolaSeq, ChainSeq, HoleSeq released |
| if(group1 == 1) |
| { |
| if(pVoronoiStorage->SiteStorage!=NULL) |
| cvReleaseMemStorage(&pVoronoiStorage->SiteStorage); |
| if(pVoronoiStorage->EdgeStorage!=NULL) |
| cvReleaseMemStorage(&pVoronoiStorage->EdgeStorage); |
| if(pVoronoiStorage->NodeStorage!=NULL) |
| cvReleaseMemStorage(&pVoronoiStorage->NodeStorage); |
| } |
| if(group2 == 1) |
| { |
| if(pVoronoiStorage->ParabolaStorage!=NULL) |
| cvReleaseMemStorage(&pVoronoiStorage->ParabolaStorage); |
| if(pVoronoiStorage->ChainStorage!=NULL) |
| cvReleaseMemStorage(&pVoronoiStorage->ChainStorage); |
| if(pVoronoiStorage->DirectionStorage!=NULL) |
| cvReleaseMemStorage(&pVoronoiStorage->DirectionStorage); |
| if(pVoronoiStorage->HoleStorage != NULL) |
| cvReleaseMemStorage(&pVoronoiStorage->HoleStorage); |
| } |
| }// end of _cvReleaseVoronoiStorage |
| |
| static int _cvConvert(CvVoronoiDiagram2D* VoronoiDiagram, |
| CvVoronoiDiagramInt VoronoiDiagramInt, |
| CvSet* &SiteSeq, |
| CvSeqWriter &NodeWriter, |
| CvSeqWriter &EdgeWriter, |
| CvMemStorage* VoronoiStorage, |
| int contour_orientation) |
| { |
| if(contour_orientation == 1) |
| return _cvConvertSameOrientation(VoronoiDiagram,VoronoiDiagramInt,SiteSeq,NodeWriter, |
| EdgeWriter,VoronoiStorage); |
| else |
| return _cvConvertChangeOrientation(VoronoiDiagram,VoronoiDiagramInt,SiteSeq,NodeWriter, |
| EdgeWriter,VoronoiStorage); |
| }// end of _cvConvert |
| |
| static int _cvConvertSameOrientation(CvVoronoiDiagram2D* VoronoiDiagram, |
| CvVoronoiDiagramInt VoronoiDiagramInt, |
| CvSet* &NewSiteSeqPrev, |
| CvSeqWriter &NodeWriter, |
| CvSeqWriter &EdgeWriter, |
| CvMemStorage* VoronoiStorage) |
| { |
| CvSeq* SiteSeq = VoronoiDiagramInt.SiteSeq; |
| CvSeq* EdgeSeq = VoronoiDiagramInt.EdgeSeq; |
| CvSeq* NodeSeq = VoronoiDiagramInt.NodeSeq; |
| |
| |
| CvMemStorage *NewSiteStorage = cvCreateChildMemStorage(VoronoiStorage); |
| CvSet *NewSiteSeq = NULL,*CurrNewSiteSeq = NULL, *PrevNewSiteSeq = NULL;; |
| CvSeqWriter SiteWriter; |
| |
| CvVoronoiSite2D NewSite = {{0,0},{0,0},{0,0}},NewSite_prev; |
| CvVoronoiSite2D *pNewSite, *pNewSite_prev = &NewSite_prev; |
| pCvVoronoiSite pSite,pFirstSite; |
| |
| CvVoronoiEdge2D NewEdge = {{0,0},{0,0},{0,0,0,0}}; |
| CvVoronoiEdge2D *pNewEdge1, *pNewEdge2; |
| pCvVoronoiEdge pEdge; |
| |
| CvVoronoiNode2D* pNode1, *pNode2; |
| CvVoronoiNode2D Node; |
| Node.next_free = NULL; |
| |
| for(CvSeq* CurrSiteSeq = SiteSeq;\ |
| CurrSiteSeq != NULL;\ |
| CurrSiteSeq = NEXT_SEQ(CurrSiteSeq,SiteSeq)) |
| { |
| CurrNewSiteSeq = cvCreateSet(0,sizeof(CvSet),sizeof(CvVoronoiSite2D), NewSiteStorage); |
| if(!NewSiteSeq) |
| NewSiteSeq = PrevNewSiteSeq = CurrNewSiteSeq; |
| else if(PrevNewSiteSeq->v_prev == NULL) |
| { |
| PrevNewSiteSeq->v_next = (CvSeq*)CurrNewSiteSeq; |
| CurrNewSiteSeq->v_prev = (CvSeq*)PrevNewSiteSeq; |
| } |
| else |
| { |
| PrevNewSiteSeq->h_next = (CvSeq*)CurrNewSiteSeq; |
| CurrNewSiteSeq->h_prev = (CvSeq*)PrevNewSiteSeq; |
| CurrNewSiteSeq->v_prev = (CvSeq*)PrevNewSiteSeq->v_prev; |
| } |
| PrevNewSiteSeq = CurrNewSiteSeq; |
| |
| pSite = pFirstSite = (pCvVoronoiSite)cvGetSeqElem(CurrSiteSeq, 0); |
| while(pSite->prev_site->node1 == pSite->prev_site->node2)\ |
| pSite = pSite->next_site; |
| pFirstSite = pSite; |
| |
| pNewSite_prev = &NewSite_prev; |
| cvStartAppendToSeq((CvSeq*)CurrNewSiteSeq, &SiteWriter); |
| do |
| { |
| pNewSite = _cvWriteSeqElem(&NewSite,SiteWriter); |
| pNewSite->next[0] = pNewSite_prev; |
| pNewSite_prev->next[1] = pNewSite; |
| pEdge = pSite->edge1; |
| if(!pEdge || !pEdge->node1 || !pEdge->node2) |
| return 0; |
| |
| if(pEdge->site == NULL) |
| { |
| pNewEdge1 = (CvVoronoiEdge2D*)pEdge->twin_edge; |
| pNewEdge1->site[1] = pNewSite; |
| pNewSite->node[0] = pNewEdge1->node[0]; |
| } |
| else |
| { |
| pNewEdge1 = _cvWriteSeqElem(&NewEdge,EdgeWriter); |
| pNewEdge1->site[0] = pNewSite; |
| |
| pNode1 = _cvWriteSeqElem(&Node,NodeWriter); |
| pNode2 = _cvWriteSeqElem(&Node,NodeWriter); |
| pNode1->pt.x = pEdge->node1->node.x; |
| pNode1->pt.y = pEdge->node1->node.y; |
| pNode1->radius = pEdge->node1->radius; |
| pNode2->pt.x = pEdge->node2->node.x; |
| pNode2->pt.y = pEdge->node2->node.y; |
| pNode2->radius = pEdge->node2->radius; |
| pNewEdge1->node[0] = pNode1; |
| pNewEdge1->node[1] = pNode2; |
| |
| pNewSite->node[0] = pNewEdge1->node[1]; |
| |
| if(!pNewEdge1->node[0] || !pNewEdge1->node[1]) |
| return 0; |
| pEdge->twin_edge->site = NULL; |
| pEdge->twin_edge->twin_edge = (pCvVoronoiEdge)pNewEdge1; |
| } |
| pNewSite->edge[1] = pNewEdge1; |
| pEdge = pEdge->prev_edge; |
| while((pEdge != NULL && CurrSiteSeq->total>1) || |
| (pEdge != pSite->edge2 && CurrSiteSeq->total == 1)) |
| { |
| if(pEdge->site == NULL) |
| { |
| pNewEdge2 = (CvVoronoiEdge2D*)pEdge->twin_edge; |
| pNewEdge2->site[1] = pNewSite; |
| if(CV_VORONOIEDGE2D_BEGINNODE(pNewEdge1,pNewSite) != pNewEdge2->node[0]) |
| { |
| cvFlushSeqWriter(&NodeWriter); |
| // cvSetRemove((CvSet*)VoronoiDiagram,VoronoiDiagram->total-1); |
| pNewEdge1->node[0] = pNewEdge2->node[0]; |
| } |
| } |
| else |
| { |
| pNewEdge2 = _cvWriteSeqElem(&NewEdge,EdgeWriter); |
| pNewEdge2->site[0] = pNewSite; |
| |
| pNode1 = _cvWriteSeqElem(&Node,NodeWriter); |
| pNode1->pt.x = pEdge->node1->node.x; |
| pNode1->pt.y = pEdge->node1->node.y; |
| pNode1->radius = pEdge->node1->radius; |
| pNewEdge2->node[0] = pNode1; |
| |
| if(pNewEdge1->site[0] == pNewSite) |
| pNewEdge2->node[1] = pNewEdge1->node[0]; |
| else |
| pNewEdge2->node[1] = pNewEdge1->node[1]; |
| |
| if(!pNewEdge1->node[0] || !pNewEdge1->node[1]) |
| return 0; |
| pEdge->twin_edge->site = NULL; |
| pEdge->twin_edge->twin_edge = (pCvVoronoiEdge)pNewEdge2; |
| } |
| if(pNewEdge1->site[0] == pNewSite) |
| pNewEdge1->next[2] = pNewEdge2; |
| else |
| pNewEdge1->next[3] = pNewEdge2; |
| |
| if(pNewEdge2->site[0] == pNewSite) |
| pNewEdge2->next[0] = pNewEdge1; |
| else |
| pNewEdge2->next[1] = pNewEdge1; |
| |
| pEdge = pEdge->prev_edge; |
| pNewEdge1 = pNewEdge2; |
| } |
| pNewSite->edge[0] = pNewEdge1; |
| pNewSite->node[1] = pNewEdge1->node[0]; |
| |
| if(pSite->node1 == pSite->node2 && pSite != pSite->next_site && pNewEdge1->node[0] != pNewEdge1->node[1]) |
| { |
| cvFlushSeqWriter(&NodeWriter); |
| // cvSetRemove((CvSet*)VoronoiDiagram,VoronoiDiagram->total-1); |
| pNewSite->node[1] = pNewEdge1->node[0] = pNewSite->node[0]; |
| } |
| |
| pNewSite_prev = pNewSite; |
| pSite = pSite->next_site; |
| }while(pSite != pFirstSite); |
| pNewSite->node[1] = pNewEdge1->node[1]; |
| if(pSite == pSite->next_site) |
| { |
| Node.pt.x = pSite->node1->node.x; |
| Node.pt.y = pSite->node1->node.y; |
| Node.radius = 0; |
| pNewSite->node[0] = pNewSite->node[1] = _cvWriteSeqElem(&Node,NodeWriter); |
| } |
| |
| cvEndWriteSeq(&SiteWriter); |
| pNewSite = (CvVoronoiSite2D*)cvGetSetElem(CurrNewSiteSeq, 0); |
| pNewSite->next[0] = pNewSite_prev; |
| pNewSite_prev->next[1] = pNewSite; |
| } |
| |
| cvReleaseMemStorage(&(SiteSeq->storage)); |
| cvReleaseMemStorage(&(EdgeSeq->storage)); |
| cvReleaseMemStorage(&(NodeSeq->storage)); |
| |
| if(NewSiteSeqPrev == NULL) |
| VoronoiDiagram->sites = NewSiteSeq; |
| else |
| { |
| NewSiteSeqPrev->h_next = (CvSeq*)NewSiteSeq; |
| NewSiteSeq->h_prev = (CvSeq*)NewSiteSeqPrev; |
| } |
| |
| NewSiteSeqPrev = NewSiteSeq; |
| return 1; |
| }//end of _cvConvertSameOrientation |
| |
| static int _cvConvertChangeOrientation(CvVoronoiDiagram2D* VoronoiDiagram, |
| CvVoronoiDiagramInt VoronoiDiagramInt, |
| CvSet* &NewSiteSeqPrev, |
| CvSeqWriter &NodeWriter, |
| CvSeqWriter &EdgeWriter, |
| CvMemStorage* VoronoiStorage) |
| { |
| // pNewSite->edge[1] = pSite->edge2 |
| // pNewSite->edge[0] = pSite->edge1 |
| |
| CvSeq* SiteSeq = VoronoiDiagramInt.SiteSeq; |
| CvSeq* EdgeSeq = VoronoiDiagramInt.EdgeSeq; |
| CvSeq* NodeSeq = VoronoiDiagramInt.NodeSeq; |
| |
| |
| CvMemStorage *NewSiteStorage = cvCreateChildMemStorage(VoronoiStorage); |
| CvSet *NewSiteSeq = NULL,*CurrNewSiteSeq = NULL, *PrevNewSiteSeq = NULL;; |
| CvSeqWriter SiteWriter; |
| |
| CvVoronoiSite2D NewSite = {{0,0},{0,0},{0,0}},NewSite_prev; |
| CvVoronoiSite2D *pNewSite, *pNewSite_prev = &NewSite_prev; |
| pCvVoronoiSite pSite,pFirstSite; |
| |
| CvVoronoiEdge2D NewEdge = {{0,0},{0,0},{0,0,0,0}}; |
| CvVoronoiEdge2D *pNewEdge1, *pNewEdge2; |
| pCvVoronoiEdge pEdge; |
| |
| CvVoronoiNode2D* pNode1, *pNode2; |
| CvVoronoiNode2D Node; |
| Node.next_free = NULL; |
| |
| for(CvSeq* CurrSiteSeq = SiteSeq;\ |
| CurrSiteSeq != NULL;\ |
| CurrSiteSeq = NEXT_SEQ(CurrSiteSeq,SiteSeq)) |
| { |
| CurrNewSiteSeq = cvCreateSet(0,sizeof(CvSet),sizeof(CvVoronoiSite2D), NewSiteStorage); |
| if(!NewSiteSeq) |
| NewSiteSeq = PrevNewSiteSeq = CurrNewSiteSeq; |
| else if(PrevNewSiteSeq->v_prev == NULL) |
| { |
| PrevNewSiteSeq->v_next = (CvSeq*)CurrNewSiteSeq; |
| CurrNewSiteSeq->v_prev = (CvSeq*)PrevNewSiteSeq; |
| } |
| else |
| { |
| PrevNewSiteSeq->h_next = (CvSeq*)CurrNewSiteSeq; |
| CurrNewSiteSeq->h_prev = (CvSeq*)PrevNewSiteSeq; |
| CurrNewSiteSeq->v_prev = (CvSeq*)PrevNewSiteSeq->v_prev; |
| } |
| PrevNewSiteSeq = CurrNewSiteSeq; |
| |
| pSite = (pCvVoronoiSite)cvGetSeqElem(CurrSiteSeq, 0); |
| while(pSite->next_site->node1 == pSite->next_site->node2)\ |
| pSite = pSite->next_site; |
| pFirstSite = pSite; |
| |
| pNewSite_prev = &NewSite_prev; |
| cvStartAppendToSeq((CvSeq*)CurrNewSiteSeq, &SiteWriter); |
| do |
| { |
| pNewSite = _cvWriteSeqElem(&NewSite,SiteWriter); |
| pNewSite->next[0] = pNewSite_prev; |
| pNewSite_prev->next[1] = pNewSite; |
| |
| pEdge = pSite->edge2; |
| if(!pEdge || !pEdge->node1 || !pEdge->node2) |
| return 0; |
| |
| if(pEdge->site == NULL) |
| { |
| pNewEdge1 = (CvVoronoiEdge2D*)pEdge->twin_edge; |
| pNewEdge1->site[1] = pNewSite; |
| pNewSite->node[0] = pNewEdge1->node[0]; |
| } |
| else |
| { |
| pNewEdge1 = _cvWriteSeqElem(&NewEdge,EdgeWriter); |
| pNewEdge1->site[0] = pNewSite; |
| |
| pNode1 = _cvWriteSeqElem(&Node,NodeWriter); |
| pNode2 = _cvWriteSeqElem(&Node,NodeWriter); |
| pNode1->pt.x = pEdge->node1->node.x; |
| pNode1->pt.y = pEdge->node1->node.y; |
| pNode1->radius = pEdge->node1->radius; |
| pNode2->pt.x = pEdge->node2->node.x; |
| pNode2->pt.y = pEdge->node2->node.y; |
| pNode2->radius = pEdge->node2->radius; |
| pNewEdge1->node[0] = pNode2; |
| pNewEdge1->node[1] = pNode1; |
| |
| pNewSite->node[0] = pNewEdge1->node[1]; |
| |
| if(!pNewEdge1->node[0] || !pNewEdge1->node[1]) |
| return 0; |
| pEdge->twin_edge->site = NULL; |
| pEdge->twin_edge->twin_edge = (pCvVoronoiEdge)pNewEdge1; |
| } |
| pNewSite->edge[1] = pNewEdge1; |
| |
| |
| pEdge = pEdge->next_edge; |
| while((pEdge != NULL && CurrSiteSeq->total>1) || |
| (pEdge != pSite->edge1 && CurrSiteSeq->total == 1)) |
| { |
| if(pEdge->site == NULL) |
| { |
| pNewEdge2 = (CvVoronoiEdge2D*)pEdge->twin_edge; |
| pNewEdge2->site[1] = pNewSite; |
| if(CV_VORONOIEDGE2D_BEGINNODE(pNewEdge1,pNewSite) != pNewEdge2->node[0]) |
| { |
| cvFlushSeqWriter(&NodeWriter); |
| // cvSetRemove((CvSet*)VoronoiDiagram,VoronoiDiagram->total-1); |
| pNewEdge1->node[0] = pNewEdge2->node[0]; |
| } |
| } |
| else |
| { |
| pNewEdge2 = _cvWriteSeqElem(&NewEdge,EdgeWriter); |
| pNewEdge2->site[0] = pNewSite; |
| |
| pNode2 = _cvWriteSeqElem(&Node,NodeWriter); |
| pNode2->pt.x = pEdge->node2->node.x; |
| pNode2->pt.y = pEdge->node2->node.y; |
| pNode2->radius = pEdge->node2->radius; |
| pNewEdge2->node[0] = pNode2; |
| |
| if(pNewEdge1->site[0] == pNewSite) |
| pNewEdge2->node[1] = pNewEdge1->node[0]; |
| else |
| pNewEdge2->node[1] = pNewEdge1->node[1]; |
| |
| if(!pNewEdge1->node[0] || !pNewEdge1->node[1]) |
| return 0; |
| pEdge->twin_edge->site = NULL; |
| pEdge->twin_edge->twin_edge = (pCvVoronoiEdge)pNewEdge2; |
| } |
| if(pNewEdge1->site[0] == pNewSite) |
| pNewEdge1->next[2] = pNewEdge2; |
| else |
| pNewEdge1->next[3] = pNewEdge2; |
| |
| if(pNewEdge2->site[0] == pNewSite) |
| pNewEdge2->next[0] = pNewEdge1; |
| else |
| pNewEdge2->next[1] = pNewEdge1; |
| |
| pEdge = pEdge->next_edge; |
| pNewEdge1 = pNewEdge2; |
| } |
| pNewSite->edge[0] = pNewEdge1; |
| pNewSite->node[1] = pNewEdge1->node[0]; |
| |
| if(pSite->node1 == pSite->node2 && pSite != pSite->next_site && pNewEdge1->node[0] != pNewEdge1->node[1]) |
| { |
| cvFlushSeqWriter(&NodeWriter); |
| // cvSetRemove((CvSet*)VoronoiDiagram,VoronoiDiagram->total-1); |
| pNewSite->node[1] = pNewEdge1->node[0] = pNewSite->node[0]; |
| } |
| |
| pNewSite_prev = pNewSite; |
| pSite = pSite->prev_site; |
| }while(pSite != pFirstSite); |
| pNewSite->node[1] = pNewEdge1->node[1]; |
| if(pSite == pSite->next_site) |
| { |
| Node.pt.x = pSite->node1->node.x; |
| Node.pt.y = pSite->node1->node.y; |
| Node.radius = 0; |
| pNewSite->node[0] = pNewSite->node[1] = _cvWriteSeqElem(&Node,NodeWriter); |
| } |
| |
| cvEndWriteSeq(&SiteWriter); |
| pNewSite = (CvVoronoiSite2D*)cvGetSetElem(CurrNewSiteSeq, 0); |
| pNewSite->next[0] = pNewSite_prev; |
| pNewSite_prev->next[1] = pNewSite; |
| } |
| |
| cvReleaseMemStorage(&(SiteSeq->storage)); |
| cvReleaseMemStorage(&(EdgeSeq->storage)); |
| cvReleaseMemStorage(&(NodeSeq->storage)); |
| |
| if(NewSiteSeqPrev == NULL) |
| VoronoiDiagram->sites = NewSiteSeq; |
| else |
| { |
| NewSiteSeqPrev->h_next = (CvSeq*)NewSiteSeq; |
| NewSiteSeq->h_prev = (CvSeq*)NewSiteSeqPrev; |
| } |
| NewSiteSeqPrev = NewSiteSeq; |
| return 1; |
| }//end of _cvConvert |
| |
| template<class T> |
| int _cvConstructExtSites(CvVoronoiDiagramInt* pVoronoiDiagram, |
| CvSeq* ContourSeq, |
| int orientation, |
| T type) |
| { |
| const double angl_eps = 0.03; |
| CvSeq* SiteSeq = pVoronoiDiagram->SiteSeq; |
| CvSeq* NodeSeq = pVoronoiDiagram->NodeSeq; |
| //CvSeq* DirectionSeq = pVoronoiDiagram->DirectionSeq; |
| CvPointFloat Vertex1,Vertex2,Vertex3; |
| CvLeePoint<T> VertexT1,VertexT2,VertexT3; |
| |
| CvSeqReader ContourReader; |
| CvVoronoiSiteInt Site = {NULL,NULL,NULL,NULL,NULL,NULL,NULL}; |
| CvVoronoiSiteInt SiteTemp = {NULL,NULL,NULL,NULL,NULL,NULL,NULL}; |
| CvVoronoiNodeInt Node; |
| pCvVoronoiNode pNode1,pNode2; |
| pCvVoronoiSite pSite = &SiteTemp,pSite_prev = &SiteTemp; |
| pCvVoronoiSite pReflexSite = NULL; |
| int NReflexSite = 0; |
| |
| float delta_x_rc, delta_x_cl, delta_y_rc, delta_y_cl; |
| float norm_cl,norm_rc, mult_cl_rc; |
| float _sin, _cos; |
| int i; |
| |
| if(orientation == 1) |
| { |
| cvStartReadSeq(ContourSeq, &ContourReader,0); |
| CV_READ_SEQ_ELEM(VertexT1,ContourReader); |
| CV_READ_SEQ_ELEM(VertexT2,ContourReader); |
| } |
| else |
| { |
| cvStartReadSeq(ContourSeq, &ContourReader,1); |
| CV_REV_READ_SEQ_ELEM(VertexT1,ContourReader); |
| CV_REV_READ_SEQ_ELEM(VertexT2,ContourReader); |
| } |
| |
| Vertex1.x = (float)VertexT1.x; |
| Vertex1.y = (float)VertexT1.y; |
| Vertex2.x = (float)VertexT2.x; |
| Vertex2.y = (float)VertexT2.y; |
| |
| _cvInitVoronoiNode(&Node, &Vertex2); |
| pNode1 = _cvSeqPush(NodeSeq, &Node); |
| |
| delta_x_cl = Vertex2.x - Vertex1.x; |
| delta_y_cl = Vertex2.y - Vertex1.y; |
| norm_cl = (float)sqrt((double)delta_x_cl*delta_x_cl + delta_y_cl*delta_y_cl); |
| |
| for( i = 0;i<ContourSeq->total;i++) |
| { |
| if(orientation == 1) |
| { |
| CV_READ_SEQ_ELEM(VertexT3,ContourReader); |
| } |
| else |
| { |
| CV_REV_READ_SEQ_ELEM(VertexT3,ContourReader); |
| } |
| |
| Vertex3.x = (float)VertexT3.x; |
| Vertex3.y = (float)VertexT3.y; |
| |
| _cvInitVoronoiNode(&Node, &Vertex3); |
| pNode2 = _cvSeqPush(NodeSeq, &Node); |
| |
| delta_x_rc = Vertex3.x - Vertex2.x; |
| delta_y_rc = Vertex3.y - Vertex2.y; |
| norm_rc = (float)sqrt((double)delta_x_rc*delta_x_rc + delta_y_rc*delta_y_rc); |
| if(norm_rc==0) |
| continue; |
| |
| mult_cl_rc = norm_cl*norm_rc; |
| _sin = (delta_y_rc* delta_x_cl - delta_x_rc* delta_y_cl)/mult_cl_rc; |
| _cos = -(delta_x_cl*delta_x_rc + delta_y_cl*delta_y_rc)/mult_cl_rc; |
| |
| if((_sin > angl_eps) || (_sin > 0 && _cos > 0)) |
| { |
| pSite = _cvSeqPush(SiteSeq, &Site); |
| _cvInitVoronoiSite(pSite,pNode1,pNode2,pSite_prev); |
| pSite_prev->next_site = pSite; |
| } |
| else if((_sin < -angl_eps) || (_sin < 0 && _cos > 0)) |
| { |
| pSite = _cvSeqPush(SiteSeq, &Site); |
| _cvInitVoronoiSite(pSite,pNode1,pNode1,pSite_prev); |
| pReflexSite = pSite; |
| NReflexSite++; |
| pSite_prev->next_site = pSite; |
| |
| pSite_prev = pSite; |
| pSite = _cvSeqPush(SiteSeq, &Site); |
| _cvInitVoronoiSite(pSite,pNode1,pNode2,pSite_prev); |
| pSite_prev->next_site = pSite; |
| } |
| else |
| { |
| Vertex2 = Vertex3; |
| delta_y_rc = delta_y_cl + delta_y_rc; |
| delta_x_rc = delta_x_cl + delta_x_rc; |
| pSite->node2 = pNode2; |
| |
| norm_rc = (float)sqrt((double)delta_y_rc*delta_y_rc + delta_x_rc*delta_x_rc); |
| } |
| Vertex2=Vertex3; |
| delta_y_cl= delta_y_rc; |
| delta_x_cl= delta_x_rc; |
| norm_cl = norm_rc; |
| pSite_prev = pSite; |
| pNode1 = pNode2; |
| } |
| |
| if(SiteTemp.next_site==NULL) |
| return 0; |
| |
| if(ContourSeq->total - NReflexSite<2) |
| return 0; |
| |
| if(SiteSeq->total<3) |
| return 0; |
| |
| pSite->node2 = SiteTemp.next_site->node1; |
| pSite->next_site = SiteTemp.next_site; |
| SiteTemp.next_site->prev_site = pSite; |
| |
| i = 0; |
| if(pReflexSite!=NULL) |
| for(i=0; i<SiteSeq->total; i++) |
| { |
| if(pReflexSite->next_site->next_site->node1 != |
| pReflexSite->next_site->next_site->node2) |
| break; |
| else |
| pReflexSite = pReflexSite->next_site->next_site; |
| } |
| pVoronoiDiagram->reflex_site = pReflexSite; |
| return (i<SiteSeq->total); |
| }//end of _cvConstructExtSites |
| |
| template<class T> |
| int _cvConstructIntSites(CvVoronoiDiagramInt* pVoronoiDiagram, |
| CvSeq* CurrSiteSeq, |
| CvSeq* CurrContourSeq, |
| pCvVoronoiSite &pTopSite, |
| int orientation, |
| T type) |
| { |
| const double angl_eps = 0.03; |
| float min_x = (float)999999999; |
| CvSeq* SiteSeq = CurrSiteSeq; |
| CvSeq* NodeSeq = pVoronoiDiagram->NodeSeq; |
| //CvSeq* DirectionSeq = pVoronoiDiagram->DirectionSeq; |
| CvPointFloat Vertex1,Vertex2,Vertex3; |
| CvLeePoint<T> VertexT1,VertexT2,VertexT3; |
| |
| CvSeqReader ContourReader; |
| CvVoronoiSiteInt Site = {NULL,NULL,NULL,NULL,NULL,NULL,NULL}; |
| CvVoronoiSiteInt SiteTemp = {NULL,NULL,NULL,NULL,NULL,NULL,NULL}; |
| CvVoronoiNodeInt Node; |
| pCvVoronoiNode pNode1,pNode2; |
| pCvVoronoiSite pSite = &SiteTemp,pSite_prev = &SiteTemp; |
| pTopSite = NULL; |
| int NReflexSite = 0; |
| |
| if(CurrContourSeq->total == 1) |
| { |
| cvStartReadSeq(CurrContourSeq, &ContourReader,0); |
| CV_READ_SEQ_ELEM(VertexT1,ContourReader); |
| Vertex1.x = (float)VertexT1.x; |
| Vertex1.y = (float)VertexT1.y; |
| |
| _cvInitVoronoiNode(&Node, &Vertex1); |
| pNode1 = _cvSeqPush(NodeSeq, &Node); |
| pTopSite = pSite = _cvSeqPush(SiteSeq, &Site); |
| _cvInitVoronoiSite(pSite,pNode1,pNode1,pSite); |
| pSite->next_site = pSite; |
| return 1; |
| } |
| |
| float delta_x_rc, delta_x_cl, delta_y_rc, delta_y_cl; |
| float norm_cl,norm_rc, mult_cl_rc; |
| float _sin, _cos; |
| int i; |
| |
| if(orientation == 1) |
| { |
| cvStartReadSeq(CurrContourSeq, &ContourReader,0); |
| CV_READ_SEQ_ELEM(VertexT1,ContourReader); |
| CV_READ_SEQ_ELEM(VertexT2,ContourReader); |
| } |
| else |
| { |
| cvStartReadSeq(CurrContourSeq, &ContourReader,1); |
| CV_REV_READ_SEQ_ELEM(VertexT1,ContourReader); |
| CV_REV_READ_SEQ_ELEM(VertexT2,ContourReader); |
| } |
| |
| Vertex1.x = (float)VertexT1.x; |
| Vertex1.y = (float)VertexT1.y; |
| Vertex2.x = (float)VertexT2.x; |
| Vertex2.y = (float)VertexT2.y; |
| |
| _cvInitVoronoiNode(&Node, &Vertex2); |
| pNode1 = _cvSeqPush(NodeSeq, &Node); |
| |
| delta_x_cl = Vertex2.x - Vertex1.x; |
| delta_y_cl = Vertex2.y - Vertex1.y; |
| norm_cl = (float)sqrt((double)delta_x_cl*delta_x_cl + delta_y_cl*delta_y_cl); |
| for( i = 0;i<CurrContourSeq->total;i++) |
| { |
| if(orientation == 1) |
| { |
| CV_READ_SEQ_ELEM(VertexT3,ContourReader); |
| } |
| else |
| { |
| CV_REV_READ_SEQ_ELEM(VertexT3,ContourReader); |
| } |
| Vertex3.x = (float)VertexT3.x; |
| Vertex3.y = (float)VertexT3.y; |
| |
| _cvInitVoronoiNode(&Node, &Vertex3); |
| pNode2 = _cvSeqPush(NodeSeq, &Node); |
| |
| delta_x_rc = Vertex3.x - Vertex2.x; |
| delta_y_rc = Vertex3.y - Vertex2.y; |
| norm_rc = (float)sqrt((double)delta_x_rc*delta_x_rc + delta_y_rc*delta_y_rc); |
| if(norm_rc==0) |
| continue; |
| |
| mult_cl_rc = norm_cl*norm_rc; |
| _sin = (delta_y_rc* delta_x_cl - delta_x_rc* delta_y_cl)/mult_cl_rc; |
| _cos = -(delta_x_cl*delta_x_rc + delta_y_cl*delta_y_rc)/mult_cl_rc; |
| if((_sin > angl_eps) || (_sin > 0 && _cos > 0)) |
| { |
| pSite = _cvSeqPush(SiteSeq, &Site); |
| _cvInitVoronoiSite(pSite,pNode1,pNode2,pSite_prev); |
| pSite_prev->next_site = pSite; |
| } |
| else if((_sin < -angl_eps) || (_sin < 0 && _cos > 0) || (_sin == 0 && CurrContourSeq->total == 2)) |
| { |
| pSite = _cvSeqPush(SiteSeq, &Site); |
| _cvInitVoronoiSite(pSite,pNode1,pNode1,pSite_prev); |
| if(pNode1->node.x < min_x) |
| { |
| min_x = pNode1->node.x; |
| pTopSite = pSite; |
| } |
| NReflexSite++; |
| pSite_prev->next_site = pSite; |
| |
| pSite_prev = pSite; |
| pSite = _cvSeqPush(SiteSeq, &Site); |
| _cvInitVoronoiSite(pSite,pNode1,pNode2,pSite_prev); |
| pSite_prev->next_site = pSite; |
| } |
| else |
| { |
| Vertex2 = Vertex3; |
| delta_y_rc = delta_y_cl + delta_y_rc; |
| delta_x_rc = delta_x_cl + delta_x_rc; |
| norm_rc = (float)sqrt((double)delta_y_rc*delta_y_rc + delta_x_rc*delta_x_rc); |
| pSite->node2 = pNode2; |
| } |
| |
| Vertex1=Vertex2; |
| Vertex2=Vertex3; |
| delta_y_cl= delta_y_rc; |
| delta_x_cl= delta_x_rc; |
| norm_cl = norm_rc; |
| pSite_prev = pSite; |
| pNode1 = pNode2; |
| } |
| |
| if(SiteTemp.next_site==NULL) |
| return 0; |
| |
| if(NReflexSite < 3 && CurrContourSeq->total > 2 || NReflexSite < 2) |
| return 0; |
| |
| pSite->node2 = SiteTemp.next_site->node1; |
| pSite->next_site = SiteTemp.next_site; |
| SiteTemp.next_site->prev_site = pSite; |
| |
| return 1; |
| }//end of _cvConstructIntSites |
| |
| static int _cvConstructExtChains(CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| CvSeq* SiteSeq = pVoronoiDiagram->SiteSeq; |
| CvSeq* ChainSeq = pVoronoiDiagram->ChainSeq; |
| |
| CvVoronoiChainInt Chain; |
| pCvVoronoiChain pChain,pChainFirst; |
| pCvVoronoiSite pSite, pSite_prev, pSiteFirst,pReflexSite = pVoronoiDiagram->reflex_site; |
| |
| if(pReflexSite==NULL) |
| pSite = pSiteFirst = (pCvVoronoiSite)cvGetSeqElem(SiteSeq, 0); |
| else |
| { |
| while(pReflexSite->next_site->next_site->node1== |
| pReflexSite->next_site->next_site->node2) |
| pReflexSite = pReflexSite->next_site->next_site; |
| |
| pSite = pSiteFirst = pReflexSite->next_site; |
| } |
| |
| Chain.last_site = pSite; |
| _cvConstructEdges(pSite,pVoronoiDiagram); |
| pSite_prev = pSite; |
| pSite = pSite->prev_site; |
| do |
| { |
| if(pSite->node1!=pSite->node2) |
| { |
| Chain.first_site = pSite_prev; |
| pChain = _cvSeqPushFront(ChainSeq,&Chain); |
| |
| _cvConstructEdges(pSite,pVoronoiDiagram); |
| Chain.last_site = pSite; |
| Chain.next_chain = pChain; |
| } |
| else |
| { |
| pSite=pSite->prev_site; |
| _cvConstructEdges(pSite,pVoronoiDiagram); |
| _cvConstructEdges(pSite->next_site,pVoronoiDiagram); |
| } |
| pSite_prev = pSite; |
| pSite = pSite->prev_site; |
| }while(pSite!=pSiteFirst); |
| |
| Chain.first_site = pSite_prev; |
| pChain = _cvSeqPushFront(ChainSeq,&Chain); |
| pChainFirst = (pCvVoronoiChain)cvGetSeqElem(ChainSeq,ChainSeq->total - 1); |
| pChainFirst->next_chain = pChain; |
| if(ChainSeq->total < 3) |
| return 0; |
| else |
| return 1; |
| }// end of _cvConstructExtChains |
| |
| static void _cvConstructIntChains(CvVoronoiDiagramInt* pVoronoiDiagram, |
| CvSeq* CurrChainSeq, |
| CvSeq* CurrSiteSeq, |
| pCvVoronoiSite pTopSite) |
| { |
| CvSeq* ChainSeq = CurrChainSeq; |
| |
| if(CurrSiteSeq->total == 1) |
| return; |
| |
| CvVoronoiChainInt Chain = {NULL,NULL,NULL}; |
| pCvVoronoiChain pChain,pChainFirst;; |
| pCvVoronoiSite pSite, pSite_prev, pSiteFirst; |
| pSite = pSiteFirst = pTopSite->next_site; |
| |
| Chain.last_site = pSite; |
| _cvConstructEdges(pSite,pVoronoiDiagram); |
| pSite_prev = pSite; |
| pSite = pSite->prev_site; |
| do |
| { |
| if(pSite->node1!=pSite->node2) |
| { |
| Chain.first_site = pSite_prev; |
| pChain = _cvSeqPushFront(ChainSeq,&Chain); |
| |
| _cvConstructEdges(pSite,pVoronoiDiagram); |
| Chain.last_site = pSite; |
| Chain.next_chain = pChain; |
| } |
| else |
| { |
| pSite=pSite->prev_site; |
| if(pSite != pSiteFirst) |
| _cvConstructEdges(pSite,pVoronoiDiagram); |
| _cvConstructEdges(pSite->next_site,pVoronoiDiagram); |
| } |
| pSite_prev = pSite; |
| pSite = pSite->prev_site; |
| }while(pSite!=pSiteFirst && pSite!= pSiteFirst->prev_site); |
| |
| if(pSite == pSiteFirst->prev_site && ChainSeq->total == 0) |
| return; |
| |
| Chain.first_site = pSite_prev; |
| if(pSite == pSiteFirst->prev_site) |
| { |
| pChainFirst = (pCvVoronoiChain)cvGetSeqElem(ChainSeq,ChainSeq->total - 1); |
| pChainFirst->last_site = Chain.last_site; |
| pChainFirst->next_chain = Chain.next_chain; |
| return; |
| } |
| else |
| { |
| pChain = _cvSeqPushFront(ChainSeq,&Chain); |
| pChainFirst = (pCvVoronoiChain)cvGetSeqElem(ChainSeq,ChainSeq->total - 1); |
| pChainFirst->next_chain = pChain; |
| return; |
| } |
| }// end of _cvConstructIntChains |
| |
| CV_INLINE void _cvConstructEdges(pCvVoronoiSite pSite,CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| CvSeq* EdgeSeq = pVoronoiDiagram->EdgeSeq; |
| CvSeq* DirectionSeq = pVoronoiDiagram->DirectionSeq; |
| CvVoronoiEdgeInt Edge = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; |
| pCvVoronoiEdge pEdge1,pEdge2; |
| CvDirection EdgeDirection,SiteDirection; |
| float site_lengh; |
| |
| Edge.site = pSite; |
| if(pSite->node1!=pSite->node2) |
| { |
| SiteDirection.x = pSite->node2->node.x - pSite->node1->node.x; |
| SiteDirection.y = pSite->node2->node.y - pSite->node1->node.y; |
| site_lengh = (float)sqrt((double)SiteDirection.x*SiteDirection.x + SiteDirection.y * SiteDirection.y); |
| SiteDirection.x /= site_lengh; |
| SiteDirection.y /= site_lengh; |
| EdgeDirection.x = -SiteDirection.y; |
| EdgeDirection.y = SiteDirection.x; |
| Edge.direction = _cvSeqPush(DirectionSeq,&EdgeDirection); |
| pSite->direction = _cvSeqPush(DirectionSeq,&SiteDirection); |
| |
| pEdge1 = _cvSeqPush(EdgeSeq,&Edge); |
| pEdge2 = _cvSeqPush(EdgeSeq,&Edge); |
| } |
| else |
| { |
| pCvVoronoiSite pSite_prev = pSite->prev_site; |
| pCvVoronoiSite pSite_next = pSite->next_site; |
| |
| pEdge1 = _cvSeqPush(EdgeSeq,&Edge); |
| pEdge2 = _cvSeqPush(EdgeSeq,&Edge); |
| |
| pEdge2->direction = pSite_next->edge1->direction; |
| pEdge2->twin_edge = pSite_next->edge1; |
| pSite_next->edge1->twin_edge = pEdge2; |
| |
| pEdge1->direction = pSite_prev->edge2->direction; |
| pEdge1->twin_edge = pSite_prev->edge2; |
| pSite_prev->edge2->twin_edge = pEdge1; |
| } |
| |
| pEdge2->node1 = pSite->node2; |
| pEdge1->node2 = pSite->node1; |
| pSite->edge1 = pEdge1; |
| pSite->edge2 = pEdge2; |
| pEdge2->next_edge = pEdge1; |
| pEdge1->prev_edge = pEdge2; |
| }// end of _cvConstructEdges |
| |
| static int _cvConstructExtVD(CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| pCvVoronoiSite pSite_right = 0,pSite_left = 0; |
| pCvVoronoiEdge pEdge_left,pEdge_right; |
| pCvVoronoiChain pChain1, pChain2; |
| |
| pChain1 = (pCvVoronoiChain)cvGetSeqElem(pVoronoiDiagram->ChainSeq,0); |
| do |
| { |
| pChain2 = pChain1->next_chain; |
| if(pChain2->next_chain==pChain1) |
| { |
| pSite_right = pChain1->first_site; |
| pSite_left = pChain2->last_site; |
| pEdge_left = pSite_left->edge2->next_edge; |
| pEdge_right = pSite_right->edge1->prev_edge; |
| pEdge_left->prev_edge = NULL; |
| pEdge_right->next_edge = NULL; |
| pSite_right->edge1 = NULL; |
| pSite_left->edge2 = NULL; |
| } |
| |
| if(!_cvJoinChains(pChain1,pChain2,pVoronoiDiagram)) |
| return 0; |
| |
| pChain1->last_site = pChain2->last_site; |
| pChain1->next_chain = pChain2->next_chain; |
| pChain1 = pChain1->next_chain; |
| }while(pChain1->next_chain != pChain1); |
| |
| pCvVoronoiNode pEndNode = pSite_left->node2; |
| if(pSite_right->edge1==NULL) |
| return 0; |
| else |
| pSite_right->edge1->node2 = pEndNode; |
| |
| if(pSite_left->edge2==NULL) |
| return 0; |
| else |
| pSite_left->edge2->node1 = pEndNode; |
| |
| return 1; |
| }//end of _cvConstructExtVD |
| |
| static int _cvJoinChains(pCvVoronoiChain pChain1, |
| pCvVoronoiChain pChain2, |
| CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| const double dist_eps = 0.05; |
| if(pChain1->first_site == NULL || pChain1->last_site == NULL || |
| pChain2->first_site == NULL || pChain2->last_site == NULL) |
| return 0; |
| |
| CvVoronoiEdgeInt EdgeNULL = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; |
| |
| CvSeq* NodeSeq = pVoronoiDiagram->NodeSeq; |
| CvSeq* EdgeSeq = pVoronoiDiagram->EdgeSeq; |
| |
| pCvVoronoiSite pSite_left = pChain1->last_site; |
| pCvVoronoiSite pSite_right = pChain2->first_site; |
| |
| pCvVoronoiEdge pEdge_left = pSite_left->edge2->next_edge; |
| pCvVoronoiEdge pEdge_right = pSite_right->edge1->prev_edge; |
| |
| pCvVoronoiEdge pEdge_left_cur = pEdge_left; |
| pCvVoronoiEdge pEdge_right_cur = pEdge_right; |
| |
| pCvVoronoiEdge pEdge_left_prev = NULL; |
| pCvVoronoiEdge pEdge_right_next = NULL; |
| |
| pCvVoronoiNode pNode_siteleft = pChain1->first_site->node1; |
| pCvVoronoiNode pNode_siteright = pChain2->last_site->node2; |
| /*CvVoronoiSiteInt Site_left_chain = {pNode_siteleft,pNode_siteleft,NULL,NULL,NULL,NULL}; |
| CvVoronoiSiteInt Site_right_chain = {pNode_siteright,pNode_siteright,NULL,NULL,NULL,NULL};*/ |
| |
| pCvVoronoiEdge pEdge1,pEdge2; |
| CvPointFloat Point1 = {0,0}, Point2 = {0,0}; |
| |
| float radius1,radius2,dist1,dist2; |
| bool left = true,right = true; |
| |
| CvVoronoiNodeInt Node; |
| pCvVoronoiNode pNode_begin = pSite_left->node2; |
| |
| pEdge1 = pSite_left->edge2; |
| pEdge1->node2 = NULL; |
| pEdge2 = pSite_right->edge1; |
| pEdge2->node1 = NULL; |
| |
| for(;;) |
| { |
| |
| if(left) |
| pEdge1->node1 = pNode_begin; |
| if(right) |
| pEdge2->node2 = pNode_begin; |
| |
| pEdge_left = pEdge_left_cur; |
| pEdge_right = pEdge_right_cur; |
| |
| if(left&&right) |
| { |
| _cvCalcEdge(pSite_left,pSite_right,pEdge1,pVoronoiDiagram); |
| _cvMakeTwinEdge(pEdge2,pEdge1); |
| _cvStickEdgeLeftBegin(pEdge1,pEdge_left_prev,pSite_left); |
| _cvStickEdgeRightBegin(pEdge2,pEdge_right_next,pSite_right); |
| } |
| else if(!left) |
| { |
| _cvCalcEdge(pNode_siteleft,pSite_right,pEdge2,pVoronoiDiagram); |
| _cvStickEdgeRightBegin(pEdge2,pEdge_right_next,pSite_right); |
| } |
| else if(!right) |
| { |
| _cvCalcEdge(pSite_left,pNode_siteright,pEdge1,pVoronoiDiagram); |
| _cvStickEdgeLeftBegin(pEdge1,pEdge_left_prev,pSite_left); |
| } |
| |
| dist1=dist2=-1; |
| radius1 = -1; radius2 = -2; |
| |
| while(pEdge_left!=NULL) |
| { |
| if(pEdge_left->node2 == NULL) |
| { |
| pEdge_left_cur = pEdge_left = pEdge_left->next_edge; |
| if(pEdge_left == NULL) |
| break; |
| } |
| |
| if(left) |
| dist1 = _cvCalcEdgeIntersection(pEdge1, pEdge_left, &Point1,radius1); |
| else |
| dist1 = _cvCalcEdgeIntersection(pEdge2, pEdge_left, &Point1,radius1); |
| |
| if(dist1>=0) |
| break; |
| |
| pEdge_left = pEdge_left->next_edge; |
| } |
| |
| while(pEdge_right!=NULL) |
| { |
| if(pEdge_right->node1 == NULL) |
| { |
| pEdge_right_cur = pEdge_right = pEdge_right->prev_edge; |
| if(pEdge_right == NULL) |
| break; |
| } |
| |
| if(left) |
| dist2 = _cvCalcEdgeIntersection(pEdge1, pEdge_right, &Point2, radius2); |
| else |
| dist2 = _cvCalcEdgeIntersection(pEdge2, pEdge_right, &Point2, radius2); |
| |
| if(dist2>=0) |
| break; |
| |
| pEdge_right = pEdge_right->prev_edge; |
| } |
| |
| if(dist1<0&&dist2<0) |
| { |
| if(left) |
| { |
| pEdge_left = pSite_left->edge1; |
| if(pEdge_left==NULL) |
| _cvStickEdgeLeftEnd(pEdge1,NULL,pSite_left); |
| else |
| { |
| while(pEdge_left->node1!=NULL |
| &&pEdge_left->node1==pEdge_left->prev_edge->node2) |
| { |
| pEdge_left = pEdge_left->prev_edge; |
| if(pEdge_left==NULL || pEdge_left->prev_edge == NULL) |
| return 0; |
| } |
| _cvStickEdgeLeftEnd(pEdge1,pEdge_left,pSite_left); |
| } |
| } |
| if(right) |
| { |
| pEdge_right = pSite_right->edge2; |
| if(pEdge_right==NULL) |
| _cvStickEdgeRightEnd(pEdge2,NULL,pSite_right); |
| else |
| { |
| while(pEdge_right->node2!=NULL |
| && pEdge_right->node2==pEdge_right->next_edge->node1) |
| { |
| pEdge_right = pEdge_right->next_edge; |
| if(pEdge_right==NULL || pEdge_right->next_edge == NULL ) |
| return 0; |
| } |
| _cvStickEdgeRightEnd(pEdge2,pEdge_right,pSite_right); |
| } |
| } |
| return 1; |
| } |
| |
| if(fabs(dist1 - dist2)<dist_eps) |
| { |
| pNode_begin = _cvSeqPush(NodeSeq,&Node); |
| _cvInitVoronoiNode(pNode_begin, &Point2,radius2); |
| |
| pEdge1->node2 = pNode_begin; |
| pEdge2->node1 = pNode_begin; |
| |
| _cvStickEdgeLeftEnd(pEdge1,pEdge_left,pSite_left); |
| _cvTwinNULLLeft(pEdge_left_cur,pEdge_left); |
| |
| _cvStickEdgeRightEnd(pEdge2,pEdge_right,pSite_right); |
| _cvTwinNULLRight(pEdge_right_cur,pEdge_right); |
| |
| if(pEdge_left->twin_edge!=NULL&&pEdge_right->twin_edge!=NULL) |
| { |
| pEdge_left_prev = pEdge_left->twin_edge; |
| if(!pEdge_left_prev) |
| return 0; |
| pEdge_left_cur = pEdge_left_prev->next_edge; |
| pEdge_right_next = pEdge_right->twin_edge; |
| if(!pEdge_right_next) |
| return 0; |
| pEdge_right_cur = pEdge_right_next->prev_edge; |
| pSite_right = pEdge_right_next->site; |
| pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| pSite_left = pEdge_left_prev->site; |
| pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| continue; |
| } |
| |
| if(pEdge_left->twin_edge==NULL&&pEdge_right->twin_edge!=NULL) |
| { |
| pEdge_right_next = pEdge_right->twin_edge; |
| if(!pEdge_right_next) |
| return 0; |
| pEdge_right_cur = pEdge_right_next->prev_edge; |
| pSite_right = pEdge_right_next->site; |
| pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| pEdge_left_cur = NULL; |
| left = false; |
| continue; |
| } |
| |
| if(pEdge_left->twin_edge!=NULL&&pEdge_right->twin_edge==NULL) |
| { |
| pEdge_left_prev = pEdge_left->twin_edge; |
| if(!pEdge_left_prev) |
| return 0; |
| pEdge_left_cur = pEdge_left_prev->next_edge; |
| pSite_left = pEdge_left_prev->site; |
| pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| pEdge_right_cur = NULL; |
| right = false; |
| continue; |
| } |
| if(pEdge_left->twin_edge==NULL&&pEdge_right->twin_edge==NULL) |
| return 1; |
| } |
| |
| if((dist1<dist2&&dist1>=0)||(dist1>=0&&dist2<0)) |
| { |
| |
| pNode_begin = _cvSeqPush(NodeSeq,&Node); |
| _cvInitVoronoiNode(pNode_begin, &Point1,radius1); |
| pEdge1->node2 = pNode_begin; |
| _cvTwinNULLLeft(pEdge_left_cur,pEdge_left); |
| _cvStickEdgeLeftEnd(pEdge1,pEdge_left,pSite_left); |
| if(right) |
| { |
| pEdge2->node1 = pNode_begin; |
| pEdge_right_next = pEdge2; |
| pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| if(pEdge_left->twin_edge!=NULL) |
| { |
| pEdge_left_prev = pEdge_left->twin_edge; |
| if(!pEdge_left_prev) |
| return 0; |
| pEdge_left_cur = pEdge_left_prev->next_edge; |
| pSite_left = pEdge_left_prev->site; |
| pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| continue; |
| } |
| else |
| { |
| pEdge_left_cur = NULL; |
| left = false; |
| continue; |
| } |
| } |
| else |
| { |
| if(pEdge_left->twin_edge!=NULL) |
| { |
| pEdge_left_prev = pEdge_left->twin_edge; |
| if(!pEdge_left_prev) |
| return 0; |
| pEdge_left_cur = pEdge_left_prev->next_edge; |
| pSite_left = pEdge_left_prev->site; |
| pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| continue; |
| } |
| else |
| return 1; |
| |
| } |
| |
| } |
| |
| if((dist1>dist2&&dist2>=0)||(dist1<0&&dist2>=0)) |
| { |
| pNode_begin = _cvSeqPush(NodeSeq,&Node); |
| _cvInitVoronoiNode(pNode_begin, &Point2,radius2); |
| pEdge2->node1 = pNode_begin; |
| _cvTwinNULLRight(pEdge_right_cur,pEdge_right); |
| _cvStickEdgeRightEnd(pEdge2,pEdge_right,pSite_right); |
| if(left) |
| { |
| pEdge1->node2 = pNode_begin; |
| pEdge_left_prev = pEdge1; |
| pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| if(pEdge_right->twin_edge!=NULL) |
| { |
| pEdge_right_next = pEdge_right->twin_edge; |
| if(!pEdge_right_next) |
| return 0; |
| pEdge_right_cur = pEdge_right_next->prev_edge; |
| pSite_right = pEdge_right_next->site; |
| pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| continue; |
| } |
| else |
| { |
| pEdge_right_cur = NULL; |
| right = false; |
| continue; |
| } |
| } |
| else |
| { |
| if(pEdge_right->twin_edge!=NULL) |
| { |
| pEdge_right_next = pEdge_right->twin_edge; |
| if(!pEdge_right_next) |
| return 0; |
| pEdge_right_cur = pEdge_right_next->prev_edge; |
| pSite_right = pEdge_right_next->site; |
| pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| continue; |
| } |
| else |
| return 1; |
| } |
| |
| } |
| } |
| |
| }// end of _cvJoinChains |
| |
| static void _cvFindNearestSite(CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| pCvVoronoiHole pCurrHole, pHole = pVoronoiDiagram->top_hole; |
| pCvPointFloat pTopPoint,pPoint1,pPoint2; |
| CvPointFloat Direction; |
| pCvVoronoiSite pSite; |
| CvVoronoiNodeInt Node; |
| CvSeq* CurrSeq; |
| float min_distance,distance; |
| int i; |
| for(;pHole != NULL; pHole = pHole->next_hole) |
| { |
| if(pHole->error) |
| continue; |
| pTopPoint = &pHole->site_top->node1->node; |
| pCurrHole = NULL; |
| CurrSeq = pVoronoiDiagram->SiteSeq; |
| min_distance = (float)3e+34; |
| while(pCurrHole != pHole) |
| { |
| if(pCurrHole && pCurrHole->error) |
| continue; |
| pSite = (pCvVoronoiSite)cvGetSeqElem(CurrSeq,0); |
| if(CurrSeq->total == 1) |
| { |
| distance = _cvCalcDist(pTopPoint, pSite); |
| if(distance < min_distance) |
| { |
| min_distance = distance; |
| pHole->site_nearest = pSite; |
| } |
| } |
| else |
| { |
| for(i = 0; i < CurrSeq->total;i++, pSite = pSite->next_site) |
| { |
| if(pSite->node1 != pSite->node2) |
| { |
| pPoint1 = &pSite->node1->node; |
| pPoint2 = &pSite->node2->node; |
| |
| Direction.x = -pSite->direction->y; |
| Direction.y = pSite->direction->x; |
| |
| if( |
| (pTopPoint->x - pPoint2->x)*Direction.y - |
| (pTopPoint->y - pPoint2->y)*Direction.x > 0 |
| || |
| (pTopPoint->x - pPoint1->x)*Direction.y - |
| (pTopPoint->y - pPoint1->y)*Direction.x < 0 |
| || |
| (pTopPoint->x - pPoint1->x)*pSite->direction->y - |
| (pTopPoint->y - pPoint1->y)*pSite->direction->x > 0 |
| ) |
| continue; |
| |
| distance = _cvCalcDist(pTopPoint, pSite); |
| } |
| else |
| { |
| pPoint1 = &pSite->node1->node; |
| if( |
| (pTopPoint->x - pPoint1->x)*pSite->edge2->direction->y - |
| (pTopPoint->y - pPoint1->y)*pSite->edge2->direction->x > 0 |
| || |
| (pTopPoint->x - pPoint1->x)*pSite->edge1->direction->y - |
| (pTopPoint->y - pPoint1->y)*pSite->edge1->direction->x < 0 |
| ) |
| continue; |
| |
| distance = _cvCalcDist(pTopPoint, pSite); |
| } |
| |
| |
| if(distance < min_distance) |
| { |
| min_distance = distance; |
| pHole->site_nearest = pSite; |
| } |
| } |
| } |
| |
| if(pCurrHole == NULL) |
| pCurrHole = pVoronoiDiagram->top_hole; |
| else |
| pCurrHole = pCurrHole->next_hole; |
| |
| CurrSeq = pCurrHole->SiteSeq; |
| } |
| pHole->x_coord = min_distance; |
| |
| if(pHole->site_nearest->node1 == pHole->site_nearest->node2) |
| { |
| Direction.x = (pHole->site_nearest->node1->node.x - pHole->site_top->node1->node.x)/2; |
| Direction.y = (pHole->site_nearest->node1->node.y - pHole->site_top->node1->node.y)/2; |
| } |
| else |
| { |
| |
| Direction.x = pHole->site_nearest->direction->y * min_distance / 2; |
| Direction.y = - pHole->site_nearest->direction->x * min_distance / 2; |
| } |
| |
| Node.node.x = pHole->site_top->node1->node.x + Direction.x; |
| Node.node.y = pHole->site_top->node1->node.y + Direction.y; |
| pHole->node = _cvSeqPush(pVoronoiDiagram->NodeSeq, &Node); |
| } |
| }//end of _cvFindNearestSite |
| |
| static void _cvConstructIntVD(CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| pCvVoronoiChain pChain1, pChain2; |
| pCvVoronoiHole pHole; |
| int i; |
| |
| pHole = pVoronoiDiagram->top_hole; |
| |
| for(;pHole != NULL; pHole = pHole->next_hole) |
| { |
| if(pHole->ChainSeq->total == 0) |
| continue; |
| pChain1 = (pCvVoronoiChain)cvGetSeqElem(pHole->ChainSeq,0); |
| for(i = pHole->ChainSeq->total; i > 0;i--) |
| { |
| pChain2 = pChain1->next_chain; |
| if(!_cvJoinChains(pChain1,pChain2,pVoronoiDiagram)) |
| { |
| pHole->error = true; |
| break; |
| } |
| |
| pChain1->last_site = pChain2->last_site; |
| pChain1->next_chain = pChain2->next_chain; |
| pChain1 = pChain1->next_chain; |
| } |
| } |
| }// end of _cvConstructIntVD |
| |
| static int _cvFindOppositSiteCW(pCvVoronoiHole pHole, CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| pCvVoronoiSite pSite_left = pHole->site_nearest; |
| pCvVoronoiSite pSite_right = pHole->site_top; |
| pCvVoronoiNode pNode = pHole->node; |
| |
| CvDirection Direction = {-1,0}; |
| CvVoronoiEdgeInt Edge_right = {NULL,pSite_right->node1,pSite_right,NULL,NULL,NULL,NULL,&Direction}; |
| |
| pCvVoronoiEdge pEdge_left = pSite_left->edge2->next_edge; |
| pCvVoronoiEdge pEdge_right = &Edge_right; |
| |
| CvVoronoiEdgeInt Edge = {NULL,pNode,pSite_right,NULL,NULL,NULL,NULL,NULL}; |
| CvVoronoiEdgeInt Edge_cur = {NULL,NULL,NULL,NULL,NULL,NULL,NULL}; |
| pCvVoronoiEdge pEdge = &Edge; |
| |
| float radius1, radius2,dist1, dist2; |
| CvPointFloat Point1 = {0,0}, Point2 = {0,0}; |
| |
| for(;;) |
| { |
| pEdge->direction = NULL; |
| pEdge->parabola = NULL; |
| _cvCalcEdge(pSite_left,pSite_right,pEdge,pVoronoiDiagram); |
| |
| dist1=dist2=-1; |
| radius1 = -1; radius2 = -2; |
| while(pEdge_left!=NULL) |
| { |
| dist1 = _cvCalcEdgeIntersection(pEdge, pEdge_left, &Point1,radius1); |
| if(dist1>=0) |
| break; |
| pEdge_left = pEdge_left->next_edge; |
| } |
| |
| dist2 = _cvCalcEdgeIntersection(pEdge, pEdge_right, &Point2, radius2); |
| if(dist2>=0 && dist1 >= dist2) |
| { |
| pHole->site_opposite = pSite_left; |
| pNode->node = Point2; |
| return 1; |
| } |
| |
| if(dist1<0) |
| return 0; |
| |
| Edge_cur = *pEdge_left->twin_edge; |
| Edge_cur.node1 = pNode; |
| pEdge_left = &Edge_cur; |
| |
| pSite_left = pEdge_left->site; |
| pNode->node = Point1; |
| } |
| }//end of _cvFindOppositSiteCW |
| |
| static int _cvFindOppositSiteCCW(pCvVoronoiHole pHole,CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| pCvVoronoiSite pSite_right = pHole->site_nearest; |
| pCvVoronoiSite pSite_left = pHole->site_top; |
| pCvVoronoiNode pNode = pHole->node; |
| |
| CvDirection Direction = {-1,0}; |
| CvVoronoiEdgeInt Edge_left = {pSite_left->node1,NULL,pSite_left,NULL,NULL,NULL, NULL, &Direction}; |
| |
| pCvVoronoiEdge pEdge_left = &Edge_left; |
| pCvVoronoiEdge pEdge_right = pSite_right->edge1->prev_edge; |
| |
| CvVoronoiEdgeInt Edge = {NULL,pNode,pSite_left,NULL,NULL,NULL,NULL}; |
| CvVoronoiEdgeInt Edge_cur = {NULL,NULL,NULL,NULL,NULL,NULL,NULL}; |
| pCvVoronoiEdge pEdge = &Edge; |
| |
| double dist1, dist2; |
| float radius1, radius2; |
| CvPointFloat Point1 = {0,0}, Point2 = {0,0}; |
| |
| for(;;) |
| { |
| pEdge->direction = NULL; |
| pEdge->parabola = NULL; |
| _cvCalcEdge(pSite_left,pSite_right,pEdge,pVoronoiDiagram); |
| |
| dist1=dist2=-1; |
| radius1 = -1; radius2 = -2; |
| while(pEdge_right!=NULL) |
| { |
| dist1 = _cvCalcEdgeIntersection(pEdge, pEdge_right, &Point1,radius2); |
| if(dist1>=0) |
| break; |
| pEdge_right = pEdge_right->prev_edge; |
| } |
| |
| dist2 = _cvCalcEdgeIntersection(pEdge, pEdge_left, &Point2, radius1); |
| if(dist2>=0 && dist1 > dist2) |
| { |
| pHole->site_opposite = pSite_right; |
| pNode->node = Point2; |
| return 1; |
| } |
| |
| if(dist1<0) |
| return 0; |
| |
| Edge_cur = *pEdge_right->twin_edge; |
| Edge_cur.node2 = pNode; |
| pEdge_right = &Edge_cur; |
| |
| pSite_right = pEdge_right->site; |
| pNode->node = Point1; |
| } |
| }//end of _cvFindOppositSiteCCW |
| |
| static int _cvMergeVD(pCvVoronoiHole pHole,CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| pCvVoronoiSite pSite_left_first = pHole->site_top; |
| pCvVoronoiSite pSite_right_first = pHole->site_opposite; |
| pCvVoronoiNode pNode_begin = pHole->node; |
| if(pSite_left_first == NULL || pSite_right_first == NULL || pNode_begin == NULL) |
| return 0; |
| |
| pCvVoronoiSite pSite_left = pSite_left_first; |
| pCvVoronoiSite pSite_right = pSite_right_first; |
| |
| const double dist_eps = 0.05; |
| CvVoronoiEdgeInt EdgeNULL = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; |
| |
| CvSeq* NodeSeq = pVoronoiDiagram->NodeSeq; |
| CvSeq* EdgeSeq = pVoronoiDiagram->EdgeSeq; |
| |
| pCvVoronoiEdge pEdge_left = NULL; |
| if(pSite_left->edge2 != NULL) |
| pEdge_left = pSite_left->edge2->next_edge; |
| |
| pCvVoronoiEdge pEdge_right = pSite_right->edge1; |
| pCvVoronoiEdge pEdge_left_cur = pEdge_left; |
| pCvVoronoiEdge pEdge_right_cur = pEdge_right; |
| |
| pCvVoronoiEdge pEdge_left_prev = NULL; |
| pCvVoronoiEdge pEdge_right_next = NULL; |
| |
| pCvVoronoiEdge pEdge1,pEdge2,pEdge1_first, pEdge2_first; |
| CvPointFloat Point1 = {0,0}, Point2 = {0,0}; |
| |
| float radius1,radius2,dist1,dist2; |
| |
| CvVoronoiNodeInt Node; |
| |
| pEdge1_first = pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL);; |
| pEdge2_first = pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL);; |
| pEdge1->site = pSite_left_first; |
| pEdge2->site = pSite_right_first; |
| |
| do |
| { |
| pEdge1->node1 = pEdge2->node2 = pNode_begin; |
| |
| pEdge_left = pEdge_left_cur; |
| pEdge_right = pEdge_right_cur->prev_edge; |
| |
| _cvCalcEdge(pSite_left,pSite_right,pEdge1,pVoronoiDiagram); |
| _cvMakeTwinEdge(pEdge2,pEdge1); |
| |
| if(pEdge_left_prev != NULL) |
| _cvStickEdgeLeftBegin(pEdge1,pEdge_left_prev,pSite_left); |
| if(pEdge_right_next != NULL) |
| _cvStickEdgeRightBegin(pEdge2,pEdge_right_next,pSite_right); |
| |
| dist1=dist2=-1; |
| radius1 = -1; radius2 = -2; |
| |
| //LEFT: |
| while(pEdge_left!=NULL) |
| { |
| if(pEdge_left->node2 == NULL) |
| pEdge_left_cur = pEdge_left = pEdge_left->next_edge; |
| |
| dist1 = _cvCalcEdgeIntersection(pEdge1, pEdge_left, &Point1,radius1); |
| if(dist1>=0) |
| goto RIGHT; |
| pEdge_left = pEdge_left->next_edge; |
| } |
| |
| RIGHT: |
| while(pEdge_right!=NULL) |
| { |
| dist2 = _cvCalcEdgeIntersection(pEdge1, pEdge_right, &Point2,radius2); |
| if(dist2>=0) |
| goto RESULTHANDLING; |
| |
| pEdge_right = pEdge_right->prev_edge; |
| } |
| pEdge_right = pEdge_right_cur; |
| dist2 = _cvCalcEdgeIntersection(pEdge1, pEdge_right, &Point2, radius2); |
| |
| RESULTHANDLING: |
| if(dist1<0&&dist2<0) |
| return 0; |
| |
| if(fabs(dist1 - dist2)<dist_eps) |
| { |
| pNode_begin = _cvSeqPush(NodeSeq,&Node); |
| _cvInitVoronoiNode(pNode_begin, &Point2,radius2); |
| |
| pEdge1->node2 = pNode_begin; |
| pEdge2->node1 = pNode_begin; |
| |
| pEdge_right_cur = _cvDivideRightEdge(pEdge_right,pNode_begin,EdgeSeq); |
| |
| _cvStickEdgeLeftEnd(pEdge1,pEdge_left,pSite_left); |
| _cvStickEdgeRightEnd(pEdge2,pEdge_right,pSite_right); |
| |
| pEdge_left_prev = pEdge_left->twin_edge; |
| if(!pEdge_left_prev) |
| return 0; |
| pEdge_left_cur = pEdge_left_prev->next_edge; |
| pSite_left = pEdge_left_prev->site; |
| pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| |
| pEdge_right_next = pEdge_right->twin_edge; |
| if(!pEdge_right_next) |
| return 0; |
| pSite_right = pEdge_right_next->site; |
| pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| |
| continue; |
| } |
| |
| if((dist1<dist2&&dist1>=0)||(dist1>=0&&dist2<0)) |
| { |
| pNode_begin = _cvSeqPush(NodeSeq,&Node); |
| _cvInitVoronoiNode(pNode_begin, &Point1,radius1); |
| |
| pEdge1->node2 = pNode_begin; |
| _cvStickEdgeLeftEnd(pEdge1,pEdge_left,pSite_left); |
| |
| pEdge2->node1 = pNode_begin; |
| pEdge_right_next = pEdge2; |
| pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| |
| pEdge_left_prev = pEdge_left->twin_edge; |
| if(!pEdge_left_prev) |
| return 0; |
| pEdge_left_cur = pEdge_left_prev->next_edge; |
| pSite_left = pEdge_left_prev->site; |
| pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| |
| continue; |
| } |
| |
| if((dist1>dist2&&dist2>=0)||(dist1<0&&dist2>=0)) |
| { |
| pNode_begin = _cvSeqPush(NodeSeq,&Node); |
| _cvInitVoronoiNode(pNode_begin, &Point2,radius2); |
| |
| pEdge_right_cur = _cvDivideRightEdge(pEdge_right,pNode_begin,EdgeSeq); |
| |
| pEdge2->node1 = pNode_begin; |
| _cvStickEdgeRightEnd(pEdge2,pEdge_right,pSite_right); |
| |
| pEdge1->node2 = pNode_begin; |
| pEdge_left_prev = pEdge1; |
| pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| |
| pEdge_right_next = pEdge_right->twin_edge; |
| if(!pEdge_right_next) |
| return 0; |
| pSite_right = pEdge_right_next->site; |
| pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL); |
| |
| continue; |
| } |
| |
| }while(!(pSite_left == pSite_left_first && pSite_right == pSite_right_first)); |
| |
| pEdge1_first->node1 = pNode_begin; |
| pEdge2_first->node2 = pNode_begin; |
| _cvStickEdgeLeftBegin(pEdge1_first,pEdge_left_prev,pSite_left_first); |
| _cvStickEdgeRightBegin(pEdge2_first,pEdge_right_next,pSite_right_first); |
| |
| if(pSite_left_first->edge2 == NULL) |
| pSite_left_first->edge2 = pSite_left_first->edge1 = pEdge1_first; |
| return 1; |
| }// end of _cvMergeVD |
| |
| |
| /* /////////////////////////////////////////////////////////////////////////////////////// |
| // Computation of bisectors // |
| /////////////////////////////////////////////////////////////////////////////////////// */ |
| |
| void _cvCalcEdge(pCvVoronoiSite pSite_left, |
| pCvVoronoiSite pSite_right, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| if((pSite_left->node1!=pSite_left->node2)&& |
| (pSite_right->node1!=pSite_right->node2)) |
| _cvCalcEdgeLL(pSite_left->direction, |
| pSite_right->direction, |
| pEdge,pVoronoiDiagram); |
| |
| else if((pSite_left->node1!=pSite_left->node2)&& |
| (pSite_right->node1 == pSite_right->node2)) |
| _cvCalcEdgeLP(pSite_left,pSite_right->node1,pEdge,pVoronoiDiagram); |
| |
| else if((pSite_left->node1==pSite_left->node2)&& |
| (pSite_right->node1!=pSite_right->node2)) |
| _cvCalcEdgePL(pSite_left->node1,pSite_right,pEdge,pVoronoiDiagram); |
| |
| else |
| _cvCalcEdgePP(&(pSite_left->node1->node), |
| &(pSite_right->node1->node), |
| pEdge,pVoronoiDiagram); |
| }//end of _cvCalcEdge |
| |
| void _cvCalcEdge(pCvVoronoiSite pSite, |
| pCvVoronoiNode pNode, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| if(pSite->node1!=pSite->node2) |
| _cvCalcEdgeLP(pSite, pNode, pEdge,pVoronoiDiagram); |
| else |
| _cvCalcEdgePP(&(pSite->node1->node), |
| &pNode->node, |
| pEdge,pVoronoiDiagram); |
| }//end of _cvCalcEdge |
| |
| void _cvCalcEdge(pCvVoronoiNode pNode, |
| pCvVoronoiSite pSite, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| if(pSite->node1!=pSite->node2) |
| _cvCalcEdgePL(pNode,pSite,pEdge,pVoronoiDiagram); |
| else |
| _cvCalcEdgePP(&pNode->node,&pSite->node1->node,pEdge,pVoronoiDiagram); |
| }//end of _cvCalcEdge |
| |
| CV_INLINE |
| void _cvCalcEdgeLL(pCvDirection pDirection1, |
| pCvDirection pDirection2, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| CvDirection Direction = {pDirection2->x - pDirection1->x, pDirection2->y - pDirection1->y}; |
| if((fabs(Direction.x)<LEE_CONST_ZERO)&&(fabs(Direction.y)<LEE_CONST_ZERO)) |
| Direction = *pDirection2; |
| pEdge->direction = _cvSeqPush(pVoronoiDiagram->DirectionSeq,&Direction);; |
| }//end of _cvCalcEdgeLL |
| |
| CV_INLINE |
| void _cvCalcEdgePP(pCvPointFloat pPoint1, |
| pCvPointFloat pPoint2, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| CvDirection Direction = {pPoint1->y - pPoint2->y,pPoint2->x - pPoint1->x}; |
| pEdge->direction = _cvSeqPush(pVoronoiDiagram->DirectionSeq,&Direction); |
| }//end of _cvCalcEdgePP |
| |
| CV_INLINE |
| void _cvCalcEdgePL(pCvVoronoiNode pFocus, |
| pCvVoronoiSite pDirectrice, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| pCvPointFloat pPoint0 = &pFocus->node; |
| pCvPointFloat pPoint1 = &pDirectrice->node1->node; |
| |
| CvDirection Vector01 = {pPoint0->x - pPoint1->x,pPoint0->y - pPoint1->y}; |
| float half_h = (Vector01.y*pDirectrice->direction->x - Vector01.x*pDirectrice->direction->y)/2; |
| CvDirection Normal = {-pDirectrice->direction->y,pDirectrice->direction->x}; |
| if(half_h < LEE_CONST_ZERO) |
| { |
| pEdge->direction = _cvSeqPush(pVoronoiDiagram->DirectionSeq,&Normal); |
| return; |
| } |
| CvVoronoiParabolaInt Parabola; |
| pCvVoronoiParabola pParabola = _cvSeqPush(pVoronoiDiagram->ParabolaSeq,&Parabola); |
| float* map = pParabola->map; |
| |
| map[1] = Normal.x; |
| map[4] = Normal.y; |
| map[0] = Normal.y; |
| map[3] = -Normal.x; |
| map[2] = pPoint0->x - Normal.x*half_h; |
| map[5] = pPoint0->y - Normal.y*half_h; |
| |
| pParabola->a = 1/(4*half_h); |
| pParabola->focus = pFocus; |
| pParabola->directrice = pDirectrice; |
| pEdge->parabola = pParabola; |
| }//end of _cvCalcEdgePL |
| |
| CV_INLINE |
| void _cvCalcEdgeLP(pCvVoronoiSite pDirectrice, |
| pCvVoronoiNode pFocus, |
| pCvVoronoiEdge pEdge, |
| CvVoronoiDiagramInt* pVoronoiDiagram) |
| { |
| pCvPointFloat pPoint0 = &pFocus->node; |
| pCvPointFloat pPoint1 = &pDirectrice->node1->node; |
| |
| CvDirection Vector01 = {pPoint0->x - pPoint1->x,pPoint0->y - pPoint1->y}; |
| float half_h = (Vector01.y*pDirectrice->direction->x - Vector01.x*pDirectrice->direction->y)/2; |
| CvDirection Normal = {-pDirectrice->direction->y,pDirectrice->direction->x}; |
| if(half_h < LEE_CONST_ZERO) |
| { |
| pEdge->direction = _cvSeqPush(pVoronoiDiagram->DirectionSeq,&Normal); |
| return; |
| } |
| CvVoronoiParabolaInt Parabola; |
| pCvVoronoiParabola pParabola = _cvSeqPush(pVoronoiDiagram->ParabolaSeq,&Parabola); |
| float* map = pParabola->map; |
| |
| map[1] = Normal.x; |
| map[4] = Normal.y; |
| map[0] = -Normal.y; |
| map[3] = Normal.x; |
| map[2] = pPoint0->x - Normal.x*half_h; |
| map[5] = pPoint0->y - Normal.y*half_h; |
| |
| pParabola->a = 1/(4*half_h); |
| pParabola->focus = pFocus; |
| pParabola->directrice = pDirectrice; |
| pEdge->parabola = pParabola; |
| }//end of _cvCalcEdgeLP |
| |
| /* /////////////////////////////////////////////////////////////////////////////////////// |
| // Computation of intersections of bisectors // |
| /////////////////////////////////////////////////////////////////////////////////////// */ |
| |
| static |
| float _cvCalcEdgeIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| CvPointFloat* pPoint, |
| float &Radius) |
| { |
| if((pEdge1->parabola==NULL)&&(pEdge2->parabola==NULL)) |
| return _cvLine_LineIntersection(pEdge1,pEdge2,pPoint,Radius); |
| if((pEdge1->parabola==NULL)&&(pEdge2->parabola!=NULL)) |
| return _cvLine_ParIntersection(pEdge1,pEdge2,pPoint,Radius); |
| if((pEdge1->parabola!=NULL)&&(pEdge2->parabola==NULL)) |
| return _cvPar_LineIntersection(pEdge1,pEdge2,pPoint,Radius); |
| if((pEdge1->parabola!=NULL)&&(pEdge2->parabola!=NULL)) |
| return _cvPar_ParIntersection(pEdge1,pEdge2,pPoint,Radius); |
| return -1; |
| }//end of _cvCalcEdgeIntersection |
| |
| static |
| float _cvLine_LineIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius) |
| { |
| if(((pEdge1->node1 == pEdge2->node1 || |
| pEdge1->node1 == pEdge2->node2) && |
| pEdge1->node1 != NULL)|| |
| ((pEdge1->node2 == pEdge2->node1 || |
| pEdge1->node2 == pEdge2->node2) && |
| pEdge1->node2 != NULL)) |
| return -1; |
| |
| CvPointFloat Point1,Point3; |
| float det; |
| float k,m; |
| float x21,x43,y43,y21,x31,y31; |
| |
| if(pEdge1->node1!=NULL) |
| { |
| Point1.x = pEdge1->node1->node.x; |
| Point1.y = pEdge1->node1->node.y; |
| } |
| else |
| { |
| Point1.x = pEdge1->node2->node.x; |
| Point1.y = pEdge1->node2->node.y; |
| } |
| x21 = pEdge1->direction->x; |
| y21 = pEdge1->direction->y; |
| |
| if(pEdge2->node2==NULL) |
| { |
| Point3.x = pEdge2->node1->node.x; |
| Point3.y = pEdge2->node1->node.y; |
| x43 = pEdge2->direction->x; |
| y43 = pEdge2->direction->y; |
| |
| } |
| else if(pEdge2->node1==NULL) |
| { |
| Point3.x = pEdge2->node2->node.x; |
| Point3.y = pEdge2->node2->node.y; |
| x43 = pEdge2->direction->x; |
| y43 = pEdge2->direction->y; |
| } |
| else |
| { |
| Point3.x = pEdge2->node1->node.x; |
| Point3.y = pEdge2->node1->node.y; |
| x43 = pEdge2->node2->node.x - Point3.x; |
| y43 = pEdge2->node2->node.y - Point3.y; |
| } |
| |
| x31 = Point3.x - Point1.x; |
| y31 = Point3.y - Point1.y; |
| |
| det = y21*x43 - x21*y43; |
| if(fabs(det) < LEE_CONST_ZERO) |
| return -1; |
| |
| k = (x43*y31 - y43*x31)/det; |
| m = (x21*y31 - y21*x31)/det; |
| |
| if(k<-LEE_CONST_ACCEPTABLE_ERROR||m<-LEE_CONST_ACCEPTABLE_ERROR) |
| return -1; |
| if(((pEdge1->node2!=NULL)&&(pEdge1->node1!=NULL))&&(k>1.f+LEE_CONST_ACCEPTABLE_ERROR)) |
| return -1; |
| if(((pEdge2->node2!=NULL)&&(pEdge2->node1!=NULL))&&(m>1.f+LEE_CONST_ACCEPTABLE_ERROR)) |
| return -1; |
| |
| pPoint->x = (float)(k*x21) + Point1.x; |
| pPoint->y = (float)(k*y21) + Point1.y; |
| |
| Radius = _cvCalcDist(pPoint,pEdge1->site); |
| return _cvPPDist(pPoint,&Point1);; |
| }//end of _cvLine_LineIntersection |
| |
| static |
| float _cvLine_ParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius) |
| { |
| if(pEdge2->node1==NULL||pEdge2->node2==NULL) |
| return _cvLine_OpenParIntersection(pEdge1,pEdge2,pPoint,Radius); |
| else |
| return _cvLine_CloseParIntersection(pEdge1,pEdge2,pPoint,Radius); |
| }//end of _cvLine_ParIntersection |
| |
| static |
| float _cvLine_OpenParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius) |
| { |
| int IntersectionNumber = 1; |
| if(((pEdge1->node1 == pEdge2->node1 || |
| pEdge1->node1 == pEdge2->node2) && |
| pEdge1->node1 != NULL)|| |
| ((pEdge1->node2 == pEdge2->node1 || |
| pEdge1->node2 == pEdge2->node2) && |
| pEdge1->node2 != NULL)) |
| IntersectionNumber = 2; |
| |
| pCvPointFloat pRayPoint1; |
| if(pEdge1->node1!=NULL) |
| pRayPoint1 = &(pEdge1->node1->node); |
| else |
| pRayPoint1 = &(pEdge1->node2->node); |
| |
| pCvDirection pDirection = pEdge1->direction; |
| float* Parabola = pEdge2->parabola->map; |
| |
| pCvPointFloat pParPoint1; |
| if(pEdge2->node1==NULL) |
| pParPoint1 = &(pEdge2->node2->node); |
| else |
| pParPoint1 = &(pEdge2->node1->node); |
| |
| float InversParabola[6]; |
| _cvCalcOrtogInverse(InversParabola, Parabola); |
| |
| CvPointFloat Point,ParPoint1_img,RayPoint1_img; |
| CvDirection Direction_img; |
| _cvCalcPointImage(&RayPoint1_img, pRayPoint1, InversParabola); |
| _cvCalcVectorImage(&Direction_img,pDirection, InversParabola); |
| |
| float c2 = pEdge2->parabola->a*Direction_img.x; |
| float c1 = -Direction_img.y; |
| float c0 = Direction_img.y* RayPoint1_img.x - Direction_img.x*RayPoint1_img.y; |
| float X[2]; |
| int N = _cvSolveEqu2thR(c2,c1,c0,X); |
| if(N==0) |
| return -1; |
| |
| _cvCalcPointImage(&ParPoint1_img, pParPoint1, InversParabola); |
| int sign_x = SIGN(Direction_img.x); |
| int sign_y = SIGN(Direction_img.y); |
| if(N==1) |
| { |
| if(X[0]<ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) |
| return -1; |
| float pr0 = (X[0]-RayPoint1_img.x)*sign_x + \ |
| (pEdge2->parabola->a*X[0]*X[0]-RayPoint1_img.y)*sign_y; |
| if(pr0 <= -LEE_CONST_ACCEPTABLE_ERROR) |
| return -1; |
| } |
| else |
| { |
| if(X[1]<ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) |
| return -1; |
| float pr0 = (X[0]-RayPoint1_img.x)*sign_x + \ |
| (pEdge2->parabola->a*X[0]*X[0]-RayPoint1_img.y)*sign_y; |
| float pr1 = (X[1]-RayPoint1_img.x)*sign_x + \ |
| (pEdge2->parabola->a*X[1]*X[1]-RayPoint1_img.y)*sign_y; |
| |
| if(pr0 <= -LEE_CONST_ACCEPTABLE_ERROR &&pr1 <= -LEE_CONST_ACCEPTABLE_ERROR) |
| return -1; |
| |
| if(pr0 >- LEE_CONST_ACCEPTABLE_ERROR && pr1 >- LEE_CONST_ACCEPTABLE_ERROR) |
| { |
| if(X[0] >= ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) |
| { |
| if(pr0>pr1) |
| _cvSwap(X[0],X[1]); |
| } |
| else |
| { |
| N=1; |
| X[0] = X[1]; |
| } |
| } |
| else if(pr0 >- LEE_CONST_ACCEPTABLE_ERROR) |
| { |
| N = 1; |
| if(X[0] < ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) |
| return -1; |
| } |
| else if(pr1 >- LEE_CONST_ACCEPTABLE_ERROR) |
| { |
| N=1; |
| X[0] = X[1]; |
| } |
| else |
| return -1; |
| } |
| |
| Point.x = X[(N-1)*(IntersectionNumber - 1)]; |
| Point.y = pEdge2->parabola->a*Point.x*Point.x; |
| |
| Radius = Point.y + 1.f/(4*pEdge2->parabola->a); |
| _cvCalcPointImage(pPoint,&Point,Parabola); |
| float dist = _cvPPDist(pPoint, pRayPoint1); |
| if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS) |
| return -1; |
| else |
| return dist; |
| }// end of _cvLine_OpenParIntersection |
| |
| static |
| float _cvLine_CloseParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius) |
| { |
| int IntersectionNumber = 1; |
| if(((pEdge1->node1 == pEdge2->node1 || |
| pEdge1->node1 == pEdge2->node2) && |
| pEdge1->node1 != NULL)|| |
| ((pEdge1->node2 == pEdge2->node1 || |
| pEdge1->node2 == pEdge2->node2) && |
| pEdge1->node2 != NULL)) |
| IntersectionNumber = 2; |
| |
| pCvPointFloat pRayPoint1; |
| if(pEdge1->node1!=NULL) |
| pRayPoint1 = &(pEdge1->node1->node); |
| else |
| pRayPoint1 = &(pEdge1->node2->node); |
| |
| pCvDirection pDirection = pEdge1->direction; |
| float* Parabola = pEdge2->parabola->map; |
| |
| pCvPointFloat pParPoint1,pParPoint2; |
| pParPoint2 = &(pEdge2->node1->node); |
| pParPoint1 = &(pEdge2->node2->node); |
| |
| |
| float InversParabola[6]; |
| _cvCalcOrtogInverse(InversParabola, Parabola); |
| |
| CvPointFloat Point,ParPoint1_img,ParPoint2_img,RayPoint1_img; |
| CvDirection Direction_img; |
| _cvCalcPointImage(&RayPoint1_img, pRayPoint1, InversParabola); |
| _cvCalcVectorImage(&Direction_img,pDirection, InversParabola); |
| |
| float c2 = pEdge2->parabola->a*Direction_img.x; |
| float c1 = -Direction_img.y; |
| float c0 = Direction_img.y* RayPoint1_img.x - Direction_img.x*RayPoint1_img.y; |
| float X[2]; |
| int N = _cvSolveEqu2thR(c2,c1,c0,X); |
| if(N==0) |
| return -1; |
| |
| _cvCalcPointImage(&ParPoint1_img, pParPoint1, InversParabola); |
| _cvCalcPointImage(&ParPoint2_img, pParPoint2, InversParabola); |
| if(ParPoint1_img.x>ParPoint2_img.x) |
| _cvSwap(ParPoint1_img,ParPoint2_img); |
| int sign_x = SIGN(Direction_img.x); |
| int sign_y = SIGN(Direction_img.y); |
| if(N==1) |
| { |
| if((X[0]<ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) || |
| (X[0]>ParPoint2_img.x + LEE_CONST_ACCEPTABLE_ERROR)) |
| return -1; |
| float pr0 = (X[0]-RayPoint1_img.x)*sign_x + \ |
| (pEdge2->parabola->a*X[0]*X[0]-RayPoint1_img.y)*sign_y; |
| if(pr0 <= -LEE_CONST_ACCEPTABLE_ERROR) |
| return -1; |
| } |
| else |
| { |
| if((X[1]<ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) || |
| (X[0]>ParPoint2_img.x + LEE_CONST_ACCEPTABLE_ERROR)) |
| return -1; |
| |
| if((X[0]<ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) && |
| (X[1]>ParPoint2_img.x + LEE_CONST_ACCEPTABLE_ERROR)) |
| return -1; |
| |
| float pr0 = (X[0]-RayPoint1_img.x)*sign_x + \ |
| (pEdge2->parabola->a*X[0]*X[0]-RayPoint1_img.y)*sign_y; |
| float pr1 = (X[1]-RayPoint1_img.x)*sign_x + \ |
| (pEdge2->parabola->a*X[1]*X[1]-RayPoint1_img.y)*sign_y; |
| |
| if(pr0 <= -LEE_CONST_ACCEPTABLE_ERROR && pr1 <= -LEE_CONST_ACCEPTABLE_ERROR) |
| return -1; |
| |
| if(pr0 > -LEE_CONST_ACCEPTABLE_ERROR && pr1 > -LEE_CONST_ACCEPTABLE_ERROR) |
| { |
| if(X[0] >= ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) |
| { |
| if(X[1] <= ParPoint2_img.x + LEE_CONST_ACCEPTABLE_ERROR) |
| { |
| if(pr0>pr1) |
| _cvSwap(X[0], X[1]); |
| } |
| else |
| N=1; |
| } |
| else |
| { |
| N=1; |
| X[0] = X[1]; |
| } |
| } |
| else if(pr0 > -LEE_CONST_ACCEPTABLE_ERROR) |
| { |
| |
| if(X[0] >= ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) |
| N=1; |
| else |
| return -1; |
| } |
| else if(pr1 > -LEE_CONST_ACCEPTABLE_ERROR) |
| { |
| if(X[1] <= ParPoint2_img.x + LEE_CONST_ACCEPTABLE_ERROR) |
| { |
| N=1; |
| X[0] = X[1]; |
| } |
| else |
| return -1; |
| } |
| else |
| return -1; |
| } |
| |
| Point.x = X[(N-1)*(IntersectionNumber - 1)]; |
| Point.y = pEdge2->parabola->a*Point.x*Point.x; |
| Radius = Point.y + 1.f/(4*pEdge2->parabola->a); |
| _cvCalcPointImage(pPoint,&Point,Parabola); |
| float dist = _cvPPDist(pPoint, pRayPoint1); |
| if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS) |
| return -1; |
| else |
| return dist; |
| }// end of _cvLine_CloseParIntersection |
| |
| static |
| float _cvPar_LineIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius) |
| { |
| if(pEdge2->node1==NULL||pEdge2->node2==NULL) |
| return _cvPar_OpenLineIntersection(pEdge1,pEdge2,pPoint,Radius); |
| else |
| return _cvPar_CloseLineIntersection(pEdge1,pEdge2,pPoint,Radius); |
| }//end _cvPar_LineIntersection |
| |
| static |
| float _cvPar_OpenLineIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius) |
| { |
| int i, IntersectionNumber = 1; |
| if(((pEdge1->node1 == pEdge2->node1 || |
| pEdge1->node1 == pEdge2->node2) && |
| pEdge1->node1 != NULL)|| |
| ((pEdge1->node2 == pEdge2->node1 || |
| pEdge1->node2 == pEdge2->node2) && |
| pEdge1->node2 != NULL)) |
| IntersectionNumber = 2; |
| |
| float* Parabola = pEdge1->parabola->map; |
| pCvPointFloat pParPoint1; |
| if(pEdge1->node1!=NULL) |
| pParPoint1 = &(pEdge1->node1->node); |
| else |
| pParPoint1 = &(pEdge1->node2->node); |
| |
| pCvPointFloat pRayPoint1; |
| if(pEdge2->node1==NULL) |
| pRayPoint1 = &(pEdge2->node2->node); |
| else |
| pRayPoint1 = &(pEdge2->node1->node); |
| pCvDirection pDirection = pEdge2->direction; |
| |
| |
| float InversParabola[6]; |
| _cvCalcOrtogInverse(InversParabola, Parabola); |
| |
| CvPointFloat Point = {0,0},ParPoint1_img,RayPoint1_img; |
| CvDirection Direction_img; |
| _cvCalcVectorImage(&Direction_img,pDirection, InversParabola); |
| _cvCalcPointImage(&RayPoint1_img, pRayPoint1, InversParabola); |
| |
| |
| float q = RayPoint1_img.y - pEdge1->parabola->a*RayPoint1_img.x*RayPoint1_img.x; |
| if(pEdge2->site->node1 == pEdge2->site->node2 && q < 0 || |
| pEdge2->site->node1 != pEdge2->site->node2 && q > 0) |
| return -1; |
| |
| float c2 = pEdge1->parabola->a*Direction_img.x; |
| float c1 = -Direction_img.y; |
| float c0 = Direction_img.y* RayPoint1_img.x - Direction_img.x*RayPoint1_img.y; |
| float X[2]; |
| int N = _cvSolveEqu2thR(c2,c1,c0,X); |
| if(N==0) |
| return -1; |
| |
| _cvCalcPointImage(&ParPoint1_img, pParPoint1, InversParabola); |
| int sign_x = SIGN(Direction_img.x); |
| int sign_y = SIGN(Direction_img.y); |
| float pr; |
| |
| if(N==2 && IntersectionNumber == 2) |
| _cvSwap(X[0], X[1]); |
| |
| for( i=0;i<N;i++) |
| { |
| if(X[i]<=ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) |
| continue; |
| pr = (X[i]-RayPoint1_img.x)*sign_x + |
| (pEdge1->parabola->a*X[i]*X[i]-RayPoint1_img.y)*sign_y; |
| if(pr <= -LEE_CONST_ACCEPTABLE_ERROR) |
| continue; |
| else |
| { |
| Point.x = X[i]; |
| break; |
| } |
| } |
| |
| if(i==N) |
| return -1; |
| |
| Point.y = pEdge1->parabola->a*Point.x*Point.x; |
| Radius = Point.y + 1.f/(4*pEdge1->parabola->a); |
| _cvCalcPointImage(pPoint,&Point,Parabola); |
| float dist = Point.x - ParPoint1_img.x; |
| if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS) |
| return -1; |
| else |
| return dist; |
| }// end of _cvPar_OpenLineIntersection |
| |
| static |
| float _cvPar_CloseLineIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius) |
| { |
| int i, IntersectionNumber = 1; |
| if(((pEdge1->node1 == pEdge2->node1 || |
| pEdge1->node1 == pEdge2->node2) && |
| pEdge1->node1 != NULL)|| |
| ((pEdge1->node2 == pEdge2->node1 || |
| pEdge1->node2 == pEdge2->node2) && |
| pEdge1->node2 != NULL)) |
| IntersectionNumber = 2; |
| |
| float* Parabola = pEdge1->parabola->map; |
| pCvPointFloat pParPoint1; |
| if(pEdge1->node1!=NULL) |
| pParPoint1 = &(pEdge1->node1->node); |
| else |
| pParPoint1 = &(pEdge1->node2->node); |
| |
| pCvPointFloat pRayPoint1,pRayPoint2; |
| pRayPoint2 = &(pEdge2->node1->node); |
| pRayPoint1 = &(pEdge2->node2->node); |
| |
| pCvDirection pDirection = pEdge2->direction; |
| float InversParabola[6]; |
| _cvCalcOrtogInverse(InversParabola, Parabola); |
| |
| CvPointFloat Point={0,0},ParPoint1_img,RayPoint1_img,RayPoint2_img; |
| CvDirection Direction_img; |
| _cvCalcPointImage(&RayPoint1_img, pRayPoint1, InversParabola); |
| _cvCalcPointImage(&RayPoint2_img, pRayPoint2, InversParabola); |
| |
| float q; |
| if(Radius == -1) |
| { |
| q = RayPoint1_img.y - pEdge1->parabola->a*RayPoint1_img.x*RayPoint1_img.x; |
| if(pEdge2->site->node1 == pEdge2->site->node2 && q < 0 || |
| pEdge2->site->node1 != pEdge2->site->node2 && q > 0) |
| return -1; |
| } |
| if(Radius == -2) |
| { |
| q = RayPoint2_img.y - pEdge1->parabola->a*RayPoint2_img.x*RayPoint2_img.x; |
| if(pEdge2->site->node1 == pEdge2->site->node2 && q < 0 || |
| pEdge2->site->node1 != pEdge2->site->node2 && q > 0) |
| return -1; |
| } |
| |
| _cvCalcPointImage(&ParPoint1_img, pParPoint1, InversParabola); |
| _cvCalcVectorImage(&Direction_img,pDirection, InversParabola); |
| |
| float c2 = pEdge1->parabola->a*Direction_img.x; |
| float c1 = -Direction_img.y; |
| float c0 = Direction_img.y* RayPoint1_img.x - Direction_img.x*RayPoint1_img.y; |
| float X[2]; |
| int N = _cvSolveEqu2thR(c2,c1,c0,X); |
| if(N==0) |
| return -1; |
| int sign_x = SIGN(RayPoint2_img.x - RayPoint1_img.x); |
| int sign_y = SIGN(RayPoint2_img.y - RayPoint1_img.y); |
| float pr_dir = (RayPoint2_img.x - RayPoint1_img.x)*sign_x + |
| (RayPoint2_img.y - RayPoint1_img.y)*sign_y; |
| float pr; |
| |
| if(N==2 && IntersectionNumber == 2) |
| _cvSwap(X[0], X[1]); |
| |
| for( i =0;i<N;i++) |
| { |
| if(X[i] <= ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) |
| continue; |
| pr = (X[i]-RayPoint1_img.x)*sign_x + \ |
| (pEdge1->parabola->a*X[i]*X[i]-RayPoint1_img.y)*sign_y; |
| if(pr <= -LEE_CONST_ACCEPTABLE_ERROR || pr>=pr_dir + LEE_CONST_ACCEPTABLE_ERROR) |
| continue; |
| else |
| { |
| Point.x = X[i]; |
| break; |
| } |
| } |
| |
| if(i==N) |
| return -1; |
| |
| Point.y = pEdge1->parabola->a*Point.x*Point.x; |
| Radius = Point.y + 1.f/(4*pEdge1->parabola->a); |
| _cvCalcPointImage(pPoint,&Point,Parabola); |
| float dist = Point.x - ParPoint1_img.x; |
| if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS) |
| return -1; |
| else |
| return dist; |
| }// end of _cvPar_CloseLineIntersection |
| |
| static |
| float _cvPar_ParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius) |
| { |
| if(pEdge2->node1==NULL||pEdge2->node2==NULL) |
| return _cvPar_OpenParIntersection(pEdge1,pEdge2,pPoint,Radius); |
| else |
| return _cvPar_CloseParIntersection(pEdge1,pEdge2,pPoint,Radius); |
| }// end of _cvPar_ParIntersection |
| |
| static |
| float _cvPar_OpenParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius) |
| { |
| int i, IntersectionNumber = 1; |
| if(((pEdge1->node1 == pEdge2->node1 || |
| pEdge1->node1 == pEdge2->node2) && |
| pEdge1->node1 != NULL)|| |
| ((pEdge1->node2 == pEdge2->node1 || |
| pEdge1->node2 == pEdge2->node2) && |
| pEdge1->node2 != NULL)) |
| IntersectionNumber = 2; |
| |
| float* Parabola1 = pEdge1->parabola->map; |
| pCvPointFloat pPar1Point1; |
| if(pEdge1->node1!=NULL) |
| pPar1Point1 = &(pEdge1->node1->node); |
| else |
| pPar1Point1 = &(pEdge1->node2->node); |
| |
| float* Parabola2 = pEdge2->parabola->map; |
| pCvPointFloat pPar2Point1; |
| if(pEdge2->node1!=NULL) |
| pPar2Point1 = &(pEdge2->node1->node); |
| else |
| pPar2Point1 = &(pEdge2->node2->node); |
| |
| CvPointFloat Point; |
| CvDirection Direction; |
| if(pEdge1->parabola->directrice==pEdge2->parabola->directrice) //common site is segment -> different focuses |
| { |
| pCvPointFloat pFocus1 = &(pEdge1->parabola->focus->node); |
| pCvPointFloat pFocus2 = &(pEdge2->parabola->focus->node); |
| |
| Point.x = (pFocus1->x + pFocus2->x)/2; |
| Point.y = (pFocus1->y + pFocus2->y)/2; |
| Direction.x = pFocus1->y - pFocus2->y; |
| Direction.y = pFocus2->x - pFocus1->x; |
| } |
| else//common site is focus -> different directrices |
| { |
| pCvVoronoiSite pDirectrice1 = pEdge1->parabola->directrice; |
| pCvPointFloat pPoint1 = &(pDirectrice1->node1->node); |
| pCvDirection pVector21 = pDirectrice1->direction; |
| |
| pCvVoronoiSite pDirectrice2 = pEdge2->parabola->directrice; |
| pCvPointFloat pPoint3 = &(pDirectrice2->node1->node); |
| pCvDirection pVector43 = pDirectrice2->direction; |
| |
| Direction.x = pVector43->x - pVector21->x; |
| Direction.y = pVector43->y - pVector21->y; |
| |
| if((fabs(Direction.x) < LEE_CONST_ZERO) && |
| (fabs(Direction.y) < LEE_CONST_ZERO)) |
| Direction = *pVector43; |
| |
| float det = pVector21->y * pVector43->x - pVector21->x * pVector43->y; |
| if(fabs(det) < LEE_CONST_ZERO) |
| { |
| Point.x = (pPoint1->x + pPoint3->x)/2; |
| Point.y = (pPoint1->y + pPoint3->y)/2; |
| } |
| else |
| { |
| float d1 = pVector21->y*pPoint1->x - pVector21->x*pPoint1->y; |
| float d2 = pVector43->y*pPoint3->x - pVector43->x*pPoint3->y; |
| Point.x = (float)((pVector43->x*d1 - pVector21->x*d2)/det); |
| Point.y = (float)((pVector43->y*d1 - pVector21->y*d2)/det); |
| } |
| } |
| |
| float InversParabola2[6]; |
| _cvCalcOrtogInverse(InversParabola2, Parabola2); |
| |
| CvPointFloat Par2Point1_img,Point_img; |
| CvDirection Direction_img; |
| _cvCalcVectorImage(&Direction_img,&Direction, InversParabola2); |
| _cvCalcPointImage(&Point_img, &Point, InversParabola2); |
| |
| float a1 = pEdge1->parabola->a; |
| float a2 = pEdge2->parabola->a; |
| float c2 = a2*Direction_img.x; |
| float c1 = -Direction_img.y; |
| float c0 = Direction_img.y* Point_img.x - Direction_img.x*Point_img.y; |
| float X[2]; |
| int N = _cvSolveEqu2thR(c2,c1,c0,X); |
| |
| if(N==0) |
| return -1; |
| |
| _cvCalcPointImage(&Par2Point1_img, pPar2Point1, InversParabola2); |
| |
| if(X[N-1]<Par2Point1_img.x) |
| return -1; |
| |
| if(X[0]<Par2Point1_img.x) |
| { |
| X[0] = X[1]; |
| N=1; |
| } |
| |
| float InversParabola1[6]; |
| CvPointFloat Par1Point1_img; |
| _cvCalcOrtogInverse(InversParabola1, Parabola1); |
| _cvCalcPointImage(&Par1Point1_img, pPar1Point1, InversParabola1); |
| float InvPar1_Par2[6]; |
| _cvCalcComposition(InvPar1_Par2,InversParabola1,Parabola2); |
| for(i=0;i<N;i++) |
| X[i] = (InvPar1_Par2[1]*a2*X[i] + InvPar1_Par2[0])*X[i] + InvPar1_Par2[2]; |
| |
| if(N!=1) |
| { |
| if((X[0]>X[1] && IntersectionNumber == 1)|| |
| (X[0]<X[1] && IntersectionNumber == 2)) |
| _cvSwap(X[0], X[1]); |
| } |
| |
| for(i = 0;i<N;i++) |
| { |
| Point.x = X[i]; |
| Point.y = a1*Point.x*Point.x; |
| if(Point.x < Par1Point1_img.x - LEE_CONST_ACCEPTABLE_ERROR) |
| continue; |
| else |
| break; |
| } |
| |
| if(i==N) |
| return -1; |
| |
| Radius = Point.y + 1.f/(4*pEdge1->parabola->a); |
| _cvCalcPointImage(pPoint,&Point,Parabola1); |
| float dist = Point.x - Par1Point1_img.x; |
| if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS) |
| return -1; |
| else |
| return dist; |
| }// end of _cvPar_OpenParIntersection |
| |
| static |
| float _cvPar_CloseParIntersection(pCvVoronoiEdge pEdge1, |
| pCvVoronoiEdge pEdge2, |
| pCvPointFloat pPoint, |
| float &Radius) |
| { |
| int i, IntersectionNumber = 1; |
| if(((pEdge1->node1 == pEdge2->node1 || |
| pEdge1->node1 == pEdge2->node2) && |
| pEdge1->node1 != NULL)|| |
| ((pEdge1->node2 == pEdge2->node1 || |
| pEdge1->node2 == pEdge2->node2) && |
| pEdge1->node2 != NULL)) |
| IntersectionNumber = 2; |
| |
| float* Parabola1 = pEdge1->parabola->map; |
| float* Parabola2 = pEdge2->parabola->map; |
| pCvPointFloat pPar1Point1; |
| if(pEdge1->node1!=NULL) |
| pPar1Point1 = &(pEdge1->node1->node); |
| else |
| pPar1Point1 = &(pEdge1->node2->node); |
| |
| pCvPointFloat pPar2Point1 = &(pEdge2->node1->node); |
| pCvPointFloat pPar2Point2 = &(pEdge2->node2->node); |
| |
| CvPointFloat Point; |
| CvDirection Direction; |
| if(pEdge1->parabola->directrice==pEdge2->parabola->directrice) //common site is segment -> different focuses |
| { |
| pCvPointFloat pFocus1 = &(pEdge1->parabola->focus->node); |
| pCvPointFloat pFocus2 = &(pEdge2->parabola->focus->node); |
| |
| Point.x = (pFocus1->x + pFocus2->x)/2; |
| Point.y = (pFocus1->y + pFocus2->y)/2; |
| Direction.x = pFocus1->y - pFocus2->y; |
| Direction.y = pFocus2->x - pFocus1->x; |
| } |
| else//common site is focus -> different directrices |
| { |
| pCvVoronoiSite pDirectrice1 = pEdge1->parabola->directrice; |
| pCvPointFloat pPoint1 = &(pDirectrice1->node1->node); |
| pCvDirection pVector21 = pDirectrice1->direction; |
| |
| pCvVoronoiSite pDirectrice2 = pEdge2->parabola->directrice; |
| pCvPointFloat pPoint3 = &(pDirectrice2->node1->node); |
| pCvDirection pVector43 = pDirectrice2->direction; |
| |
| Direction.x = pVector43->x - pVector21->x; |
| Direction.y = pVector43->y - pVector21->y; |
| |
| if((fabs(Direction.x) < LEE_CONST_ZERO) && |
| (fabs(Direction.y) < LEE_CONST_ZERO)) |
| Direction = *pVector43; |
| |
| float det = pVector21->y * pVector43->x - pVector21->x * pVector43->y; |
| if(fabs(det) < LEE_CONST_ZERO) |
| { |
| Point.x = (pPoint1->x + pPoint3->x)/2; |
| Point.y = (pPoint1->y + pPoint3->y)/2; |
| } |
| else |
| { |
| float d1 = pVector21->y*pPoint1->x - pVector21->x*pPoint1->y; |
| float d2 = pVector43->y*pPoint3->x - pVector43->x*pPoint3->y; |
| Point.x = (float)((pVector43->x*d1 - pVector21->x*d2)/det); |
| Point.y = (float)((pVector43->y*d1 - pVector21->y*d2)/det); |
| } |
| } |
| |
| |
| |
| float InversParabola2[6]; |
| _cvCalcOrtogInverse(InversParabola2, Parabola2); |
| |
| CvPointFloat Par2Point1_img,Par2Point2_img,Point_img; |
| CvDirection Direction_img; |
| _cvCalcVectorImage(&Direction_img,&Direction, InversParabola2); |
| _cvCalcPointImage(&Point_img, &Point, InversParabola2); |
| |
| float a1 = pEdge1->parabola->a; |
| float a2 = pEdge2->parabola->a; |
| float c2 = a2*Direction_img.x; |
| float c1 = -Direction_img.y; |
| float c0 = Direction_img.y* Point_img.x - Direction_img.x*Point_img.y; |
| float X[2]; |
| int N = _cvSolveEqu2thR(c2,c1,c0,X); |
| |
| if(N==0) |
| return -1; |
| |
| _cvCalcPointImage(&Par2Point1_img, pPar2Point1, InversParabola2); |
| _cvCalcPointImage(&Par2Point2_img, pPar2Point2, InversParabola2); |
| if(Par2Point1_img.x>Par2Point2_img.x) |
| _cvSwap(Par2Point1_img,Par2Point2_img); |
| |
| if(X[0]>Par2Point2_img.x||X[N-1]<Par2Point1_img.x) |
| return -1; |
| |
| if(X[0]<Par2Point1_img.x) |
| { |
| if(X[1]<Par2Point2_img.x) |
| { |
| X[0] = X[1]; |
| N=1; |
| } |
| else |
| return -1; |
| } |
| else if(X[N-1]>Par2Point2_img.x) |
| N=1; |
| |
| float InversParabola1[6]; |
| CvPointFloat Par1Point1_img; |
| _cvCalcOrtogInverse(InversParabola1, Parabola1); |
| _cvCalcPointImage(&Par1Point1_img, pPar1Point1, InversParabola1); |
| float InvPar1_Par2[6]; |
| _cvCalcComposition(InvPar1_Par2,InversParabola1,Parabola2); |
| for(i=0;i<N;i++) |
| X[i] = (InvPar1_Par2[1]*a2*X[i] + InvPar1_Par2[0])*X[i] + InvPar1_Par2[2]; |
| |
| if(N!=1) |
| { |
| if((X[0]>X[1] && IntersectionNumber == 1)|| |
| (X[0]<X[1] && IntersectionNumber == 2)) |
| _cvSwap(X[0], X[1]); |
| } |
| |
| |
| for(i = 0;i<N;i++) |
| { |
| Point.x = (float)X[i]; |
| Point.y = (float)a1*Point.x*Point.x; |
| if(Point.x < Par1Point1_img.x - LEE_CONST_ACCEPTABLE_ERROR) |
| continue; |
| else |
| break; |
| } |
| |
| if(i==N) |
| return -1; |
| |
| Radius = Point.y + 1.f/(4*a1); |
| _cvCalcPointImage(pPoint,&Point,Parabola1); |
| float dist = Point.x - Par1Point1_img.x; |
| if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS) |
| return -1; |
| else |
| return dist; |
| }// end of _cvPar_CloseParIntersection |
| |
| /* /////////////////////////////////////////////////////////////////////////////////////// |
| // Subsidiary functions // |
| /////////////////////////////////////////////////////////////////////////////////////// */ |
| |
| CV_INLINE |
| void _cvMakeTwinEdge(pCvVoronoiEdge pEdge2, |
| pCvVoronoiEdge pEdge1) |
| { |
| pEdge2->direction = pEdge1->direction; |
| pEdge2->parabola = pEdge1->parabola; |
| pEdge2->node1 = pEdge1->node2; |
| pEdge2->twin_edge = pEdge1; |
| pEdge1->twin_edge = pEdge2; |
| }//end of _cvMakeTwinEdge |
| |
| CV_INLINE |
| void _cvStickEdgeLeftBegin(pCvVoronoiEdge pEdge, |
| pCvVoronoiEdge pEdge_left_prev, |
| pCvVoronoiSite pSite_left) |
| { |
| pEdge->prev_edge = pEdge_left_prev; |
| pEdge->site = pSite_left; |
| if(pEdge_left_prev == NULL) |
| pSite_left->edge2 = pEdge; |
| else |
| { |
| pEdge_left_prev->node2 = pEdge->node1; |
| pEdge_left_prev->next_edge = pEdge; |
| } |
| }//end of _cvStickEdgeLeftBegin |
| |
| CV_INLINE |
| void _cvStickEdgeRightBegin(pCvVoronoiEdge pEdge, |
| pCvVoronoiEdge pEdge_right_next, |
| pCvVoronoiSite pSite_right) |
| { |
| pEdge->next_edge = pEdge_right_next; |
| pEdge->site = pSite_right; |
| if(pEdge_right_next == NULL) |
| pSite_right->edge1 = pEdge; |
| else |
| { |
| pEdge_right_next->node1 = pEdge->node2; |
| pEdge_right_next->prev_edge = pEdge; |
| } |
| }// end of _cvStickEdgeRightBegin |
| |
| CV_INLINE |
| void _cvStickEdgeLeftEnd(pCvVoronoiEdge pEdge, |
| pCvVoronoiEdge pEdge_left_next, |
| pCvVoronoiSite pSite_left) |
| { |
| pEdge->next_edge = pEdge_left_next; |
| if(pEdge_left_next == NULL) |
| pSite_left->edge1 = pEdge; |
| else |
| { |
| pEdge_left_next->node1 = pEdge->node2; |
| pEdge_left_next->prev_edge = pEdge; |
| } |
| }//end of _cvStickEdgeLeftEnd |
| |
| CV_INLINE |
| void _cvStickEdgeRightEnd(pCvVoronoiEdge pEdge, |
| pCvVoronoiEdge pEdge_right_prev, |
| pCvVoronoiSite pSite_right) |
| { |
| pEdge->prev_edge = pEdge_right_prev; |
| if(pEdge_right_prev == NULL) |
| pSite_right->edge2 = pEdge; |
| else |
| { |
| pEdge_right_prev->node2 = pEdge->node1; |
| pEdge_right_prev->next_edge = pEdge; |
| } |
| }//end of _cvStickEdgeRightEnd |
| |
| template <class T> CV_INLINE |
| void _cvInitVoronoiNode(pCvVoronoiNode pNode, |
| T pPoint, |
| float radius) |
| { |
| pNode->node.x = (float)pPoint->x; |
| pNode->node.y = (float)pPoint->y; |
| pNode->radius = radius; |
| }//end of _cvInitVoronoiNode |
| |
| CV_INLINE |
| void _cvInitVoronoiSite(pCvVoronoiSite pSite, |
| pCvVoronoiNode pNode1, |
| pCvVoronoiNode pNode2, |
| pCvVoronoiSite pPrev_site) |
| { |
| pSite->node1 = pNode1; |
| pSite->node2 = pNode2; |
| pSite->prev_site = pPrev_site; |
| }//end of _cvInitVoronoiSite |
| |
| template <class T> CV_INLINE |
| T _cvSeqPush(CvSeq* Seq, T pElem) |
| { |
| cvSeqPush(Seq, pElem); |
| return (T)(Seq->ptr - Seq->elem_size); |
| // return (T)cvGetSeqElem(Seq, Seq->total - 1,NULL); |
| }//end of _cvSeqPush |
| |
| template <class T> CV_INLINE |
| T _cvSeqPushFront(CvSeq* Seq, T pElem) |
| { |
| cvSeqPushFront(Seq,pElem); |
| return (T)Seq->first->data; |
| // return (T)cvGetSeqElem(Seq,0,NULL); |
| }//end of _cvSeqPushFront |
| |
| CV_INLINE |
| void _cvTwinNULLLeft(pCvVoronoiEdge pEdge_left_cur, |
| pCvVoronoiEdge pEdge_left) |
| { |
| while(pEdge_left_cur!=pEdge_left) |
| { |
| if(pEdge_left_cur->twin_edge!=NULL) |
| pEdge_left_cur->twin_edge->twin_edge = NULL; |
| pEdge_left_cur = pEdge_left_cur->next_edge; |
| } |
| }//end of _cvTwinNULLLeft |
| |
| CV_INLINE |
| void _cvTwinNULLRight(pCvVoronoiEdge pEdge_right_cur, |
| pCvVoronoiEdge pEdge_right) |
| { |
| while(pEdge_right_cur!=pEdge_right) |
| { |
| if(pEdge_right_cur->twin_edge!=NULL) |
| pEdge_right_cur->twin_edge->twin_edge = NULL; |
| pEdge_right_cur = pEdge_right_cur->prev_edge; |
| } |
| }//end of _cvTwinNULLRight |
| |
| CV_INLINE |
| void _cvSeqPushInOrder(CvVoronoiDiagramInt* pVoronoiDiagram, pCvVoronoiHole pHole) |
| { |
| pHole = _cvSeqPush(pVoronoiDiagram->HoleSeq, pHole); |
| if(pVoronoiDiagram->HoleSeq->total == 1) |
| { |
| pVoronoiDiagram->top_hole = pHole; |
| return; |
| } |
| |
| pCvVoronoiHole pTopHole = pVoronoiDiagram->top_hole; |
| pCvVoronoiHole pCurrHole; |
| if(pTopHole->x_coord >= pHole->x_coord) |
| { |
| pHole->next_hole = pTopHole; |
| pVoronoiDiagram->top_hole = pHole; |
| return; |
| } |
| |
| for(pCurrHole = pTopHole; \ |
| pCurrHole->next_hole != NULL; \ |
| pCurrHole = pCurrHole->next_hole) |
| if(pCurrHole->next_hole->x_coord >= pHole->x_coord) |
| break; |
| pHole->next_hole = pCurrHole->next_hole; |
| pCurrHole->next_hole = pHole; |
| }//end of _cvSeqPushInOrder |
| |
| CV_INLINE |
| pCvVoronoiEdge _cvDivideRightEdge(pCvVoronoiEdge pEdge,pCvVoronoiNode pNode, CvSeq* EdgeSeq) |
| { |
| CvVoronoiEdgeInt Edge1 = *pEdge; |
| CvVoronoiEdgeInt Edge2 = *pEdge->twin_edge; |
| pCvVoronoiEdge pEdge1, pEdge2; |
| |
| pEdge1 = _cvSeqPush(EdgeSeq, &Edge1); |
| pEdge2 = _cvSeqPush(EdgeSeq, &Edge2); |
| |
| if(pEdge1->next_edge != NULL) |
| pEdge1->next_edge->prev_edge = pEdge1; |
| pEdge1->prev_edge = NULL; |
| |
| if(pEdge2->prev_edge != NULL) |
| pEdge2->prev_edge->next_edge = pEdge2; |
| pEdge2->next_edge = NULL; |
| |
| pEdge1->node1 = pEdge2->node2= pNode; |
| pEdge1->twin_edge = pEdge2; |
| pEdge2->twin_edge = pEdge1; |
| return pEdge2; |
| }//end of _cvDivideRightEdge |
| |
| CV_INLINE |
| pCvVoronoiEdge _cvDivideLeftEdge(pCvVoronoiEdge pEdge,pCvVoronoiNode pNode, CvSeq* EdgeSeq) |
| { |
| CvVoronoiEdgeInt Edge1 = *pEdge; |
| CvVoronoiEdgeInt Edge2 = *pEdge->twin_edge; |
| pCvVoronoiEdge pEdge1, pEdge2; |
| |
| pEdge1 = _cvSeqPush(EdgeSeq, &Edge1); |
| pEdge2 = _cvSeqPush(EdgeSeq, &Edge2); |
| |
| if(pEdge2->next_edge != NULL) |
| pEdge2->next_edge->prev_edge = pEdge2; |
| pEdge2->prev_edge = NULL; |
| |
| if(pEdge1->prev_edge != NULL) |
| pEdge1->prev_edge->next_edge = pEdge1; |
| pEdge1->next_edge = NULL; |
| |
| pEdge1->node2 = pEdge2->node1= pNode; |
| pEdge1->twin_edge = pEdge2; |
| pEdge2->twin_edge = pEdge1; |
| return pEdge2; |
| }//end of _cvDivideLeftEdge |
| |
| template<class T> CV_INLINE |
| T _cvWriteSeqElem(T pElem, CvSeqWriter &writer) |
| { |
| if( writer.ptr >= writer.block_max ) |
| cvCreateSeqBlock( &writer); |
| |
| T ptr = (T)writer.ptr; |
| memcpy(writer.ptr, pElem, sizeof(*pElem)); |
| writer.ptr += sizeof(*pElem); |
| return ptr; |
| }//end of _cvWriteSeqElem |
| |
| /* /////////////////////////////////////////////////////////////////////////////////////// |
| // Mathematical functions // |
| /////////////////////////////////////////////////////////////////////////////////////// */ |
| |
| template<class T> CV_INLINE |
| void _cvCalcPointImage(pCvPointFloat pImgPoint,pCvPointFloat pPoint,T* A) |
| { |
| pImgPoint->x = (float)(A[0]*pPoint->x + A[1]*pPoint->y + A[2]); |
| pImgPoint->y = (float)(A[3]*pPoint->x + A[4]*pPoint->y + A[5]); |
| }//end of _cvCalcPointImage |
| |
| template <class T> CV_INLINE |
| void _cvSwap(T &x, T &y) |
| { |
| T z; z=x; x=y; y=z; |
| }//end of _cvSwap |
| |
| template <class T> CV_INLINE |
| int _cvCalcOrtogInverse(T* B, T* A) |
| { |
| int sign_det = SIGN(A[0]*A[4] - A[1]*A[3]); |
| |
| if(sign_det) |
| { |
| B[0] = A[4]*sign_det; |
| B[1] = -A[1]*sign_det; |
| B[3] = -A[3]*sign_det; |
| B[4] = A[0]*sign_det; |
| B[2] = - (B[0]*A[2]+B[1]*A[5]); |
| B[5] = - (B[3]*A[2]+B[4]*A[5]); |
| return 1; |
| } |
| else |
| return 0; |
| }//end of _cvCalcOrtogInverse |
| |
| template<class T> CV_INLINE |
| void _cvCalcVectorImage(pCvDirection pImgVector,pCvDirection pVector,T* A) |
| { |
| pImgVector->x = A[0]*pVector->x + A[1]*pVector->y; |
| pImgVector->y = A[3]*pVector->x + A[4]*pVector->y; |
| }//end of _cvCalcVectorImage |
| |
| template <class T> CV_INLINE |
| void _cvCalcComposition(T* Result,T* A,T* B) |
| { |
| Result[0] = A[0]*B[0] + A[1]*B[3]; |
| Result[1] = A[0]*B[1] + A[1]*B[4]; |
| Result[3] = A[3]*B[0] + A[4]*B[3]; |
| Result[4] = A[3]*B[1] + A[4]*B[4]; |
| Result[2] = A[0]*B[2] + A[1]*B[5] + A[2]; |
| Result[5] = A[3]*B[2] + A[4]*B[5] + A[5]; |
| }//end of _cvCalcComposition |
| |
| CV_INLINE |
| float _cvCalcDist(pCvPointFloat pPoint, pCvVoronoiSite pSite) |
| { |
| if(pSite->node1==pSite->node2) |
| return _cvPPDist(pPoint,&(pSite->node1->node)); |
| else |
| return _cvPLDist(pPoint,&(pSite->node1->node),pSite->direction); |
| }//end of _cvCalcComposition |
| |
| CV_INLINE |
| float _cvPPDist(pCvPointFloat pPoint1,pCvPointFloat pPoint2) |
| { |
| float delta_x = pPoint1->x - pPoint2->x; |
| float delta_y = pPoint1->y - pPoint2->y; |
| return (float)sqrt((double)delta_x*delta_x + delta_y*delta_y); |
| }//end of _cvPPDist |
| |
| |
| CV_INLINE |
| float _cvPLDist(pCvPointFloat pPoint,pCvPointFloat pPoint1,pCvDirection pDirection) |
| { |
| return (float)fabs(pDirection->x*(pPoint->y - pPoint1->y) - |
| pDirection->y*(pPoint->x - pPoint1->x)); |
| }//end of _cvPLDist |
| |
| template <class T> |
| int _cvSolveEqu2thR(T c2, T c1, T c0, T* X) |
| { |
| const T eps = (T)1e-6; |
| if(fabs(c2)<eps) |
| return _cvSolveEqu1th(c1,c0,X); |
| |
| T Discr = c1*c1 - c2*c0*4; |
| if(Discr<-eps) |
| return 0; |
| Discr = (T)sqrt((double)fabs(Discr)); |
| |
| if(fabs(Discr)<eps) |
| { |
| X[0] = -c1/(c2*2); |
| if(fabs(X[0])<eps) |
| X[0]=0; |
| return 1; |
| } |
| else |
| { |
| if(c1 >=0) |
| { |
| if(c2>0) |
| { |
| X[0] = (-c1 - Discr)/(2*c2); |
| X[1] = -2*c0/(c1+Discr); |
| return 2; |
| } |
| else |
| { |
| X[1] = (-c1 - Discr)/(2*c2); |
| X[0] = -2*c0/(c1+Discr); |
| return 2; |
| } |
| } |
| else |
| { |
| if(c2>0) |
| { |
| X[1] = (-c1 + Discr)/(2*c2); |
| X[0] = -2*c0/(c1-Discr); |
| return 2; |
| } |
| else |
| { |
| X[0] = (-c1 + Discr)/(2*c2); |
| X[1] = -2*c0/(c1-Discr); |
| return 2; |
| } |
| } |
| } |
| }//end of _cvSolveEqu2thR |
| |
| template <class T> CV_INLINE |
| int _cvSolveEqu1th(T c1, T c0, T* X) |
| { |
| const T eps = (T)1e-6; |
| if(fabs(c1)<eps) |
| return 0; |
| |
| X[0] = -c0/c1; |
| return 1; |
| }//end of _cvSolveEqu1th |