⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mitab_geometry.cpp

📁 在linux环境下
💻 CPP
字号:
/********************************************************************** * $Id: mitab_geometry.cpp,v 1.5 2004/06/30 20:29:04 dmorissette Exp $ * * Name:     mitab_geometry.cpp * Project:  MapInfo TAB Read/Write library * Language: C++ * Purpose:  Geometry manipulation functions. * Author:   Daniel Morissette, dmorissette@dmsolutions.ca *           Based on functions from mapprimitive.c/mapsearch.c in the source *           of UMN MapServer by Stephen Lime (http://mapserver.gis.umn.edu/) ********************************************************************** * Copyright (c) 1999-2001, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: *  * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. *  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER  * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: mitab_geometry.cpp,v $ * Revision 1.5  2004/06/30 20:29:04  dmorissette * Fixed refs to old address danmo@videotron.ca * * Revision 1.4  2001/12/18 23:42:28  daniel * Added a test in OGRPolygonLabelPoint() to prevent returning a point * outside of the polygon MBR (bug 673). * * Revision 1.3  2001/01/22 16:03:58  warmerda * expanded tabs * * Revision 1.2  2000/09/28 16:39:44  warmerda * avoid warnings for unused, and unitialized variables * * Revision 1.1  2000/09/19 17:19:40  daniel * Initial Revision * **********************************************************************/#include "ogr_geometry.h"#define OGR_NUM_RINGS(poly)   (poly->getNumInteriorRings()+1)#define OGR_GET_RING(poly, i) (i==0?poly->getExteriorRing():poly->getInteriorRing(i-1))/********************************************************************** *                   OGRPointInRing() * * Returns TRUE is point is inside ring, FALSE otherwise * * Adapted version of msPointInPolygon() from MapServer's mapsearch.c **********************************************************************/GBool OGRPointInRing(OGRPoint *poPoint, OGRLineString *poRing){    int i, j, numpoints;    GBool status = FALSE;    double x, y;    numpoints = poRing->getNumPoints();    x = poPoint->getX();    y = poPoint->getY();    for (i = 0, j = numpoints-1; i < numpoints; j = i++)     {        if ((((poRing->getY(i)<=y) && (y<poRing->getY(j))) ||              ((poRing->getY(j)<=y) && (y<poRing->getY(i)))) &&             (x < (poRing->getX(j) - poRing->getX(i)) * (y - poRing->getY(i)) /                  (poRing->getY(j) - poRing->getY(i)) + poRing->getX(i)))            status = !status;    }    return status;}/********************************************************************** *                   OGRIntersectPointPolygon() * * Instead of using ring orientation we count the number of parts the * point falls in. If odd the point is in the polygon, if 0 or even * then the point is in a hole or completely outside. * * Returns TRUE is point is inside polygon, FALSE otherwise * * Adapted version of msIntersectPointPolygon() from MapServer's mapsearch.c **********************************************************************/GBool OGRIntersectPointPolygon(OGRPoint *poPoint, OGRPolygon *poPoly) {    int i;    GBool status = FALSE;    for(i=0; i<OGR_NUM_RINGS(poPoly); i++)     {        if (OGRPointInRing(poPoint, OGR_GET_RING(poPoly, i)))         {            /* ok, the point is in a line */            status = !status;        }    }    return status;}/********************************************************************** *                   OGRPolygonLabelPoint() * * Generate a label point on the surface of a polygon. *  * The function is based on a scanline conversion routine used for polygon  * fills.  Instead of processing each line the as with drawing, the * polygon is sampled. The center of the longest sample is chosen for the  * label point. The label point is guaranteed to be in the polygon even if  * it has holes assuming the polygon is properly formed. *  * Returns OGRERR_NONE if it succeeds or OGRERR_FAILURE otherwise. * * Adapted version of msPolygonLabelPoint() from MapServer's mapprimitive.c **********************************************************************/typedef enum {CLIP_LEFT, CLIP_MIDDLE, CLIP_RIGHT} CLIP_STATE;#define CLIP_CHECK(min, a, max) ((a) < (min) ? CLIP_LEFT : ((a) > (max) ? CLIP_RIGHT : CLIP_MIDDLE));#define ROUND(a)       ( (a) + 0.5 )#define SWAP( a, b, t) ( (t) = (a), (a) = (b), (b) = (t) )#define EDGE_CHECK( x0, x, x1) ((x) < MIN( (x0), (x1)) ? CLIP_LEFT : ((x) > MAX( (x0), (x1)) ? CLIP_RIGHT : CLIP_MIDDLE ))#define NUM_SCANLINES 5int OGRPolygonLabelPoint(OGRPolygon *poPoly, OGRPoint *poLabelPoint){    double        slope;    OGRRawPoint   point1, point2;    int           i, j, k, nfound;    double        x, y, *xintersect, temp;    double        hi_y, lo_y;    int           wrong_order, n;    double        len, max_len=0;    double        skip;    OGREnvelope   oEnv;    if (poPoly == NULL)        return OGRERR_FAILURE;    poPoly->getEnvelope(&oEnv);    poLabelPoint->setX((oEnv.MaxX + oEnv.MinX)/2.0);    poLabelPoint->setY((oEnv.MaxY + oEnv.MinY)/2.0);    //if(get_centroid(p, lp, &miny, &maxy) == -1) return(-1);    if(OGRIntersectPointPolygon(poLabelPoint, poPoly) == TRUE) /* cool, done */        return OGRERR_NONE;    /* do it the hard way - scanline */    skip = (oEnv.MaxY - oEnv.MinY)/NUM_SCANLINES;    n=0;    for(j=0; j<OGR_NUM_RINGS(poPoly); j++)     {        /* count total number of points */        n += OGR_GET_RING(poPoly, j)->getNumPoints();    }    xintersect = (double *)calloc(n, sizeof(double));    if (xintersect == NULL)        return OGRERR_FAILURE;    for(k=1; k<=NUM_SCANLINES; k++)     {         /* sample the shape in the y direction */            y = oEnv.MaxY - k*skip;         /* need to find a y that won't intersect any vertices exactly */          hi_y = y - 1; /* first initializing lo_y, hi_y to be any 2 pnts on either side of lp->y */        lo_y = y + 1;        for(j=0; j<OGR_NUM_RINGS(poPoly); j++)         {            OGRLinearRing *poRing = OGR_GET_RING(poPoly,j);            if((lo_y < y) && (hi_y >= y))                 break; /* already initialized */            for(i=0; i < poRing->getNumPoints(); i++)             {                   if((lo_y < y) && (hi_y >= y))                     break; /* already initialized */                if(poRing->getY(i) < y)                    lo_y = poRing->getY(i);                if(poRing->getY(i) >= y)                    hi_y = poRing->getY(i);            }        }        n=0;        for(j=0; j<OGR_NUM_RINGS(poPoly); j++)         {            OGRLinearRing *poRing = OGR_GET_RING(poPoly,j);            for(i=0; i < poRing->getNumPoints(); i++)             {                if((poRing->getY(i) < y) &&                    ((y - poRing->getY(i)) < (y - lo_y)))                    lo_y = poRing->getY(i);                if((poRing->getY(i) >= y) &&                    ((poRing->getY(i) - y) < (hi_y - y)))                    hi_y = poRing->getY(i);            }              }        if(lo_y == hi_y)             return OGRERR_FAILURE;        else              y = (hi_y + lo_y)/2.0;                nfound = 0;        for(j=0; j<OGR_NUM_RINGS(poPoly); j++)   /* for each line */        {            OGRLinearRing *poRing = OGR_GET_RING(poPoly,j);            point1.x = poRing->getX(poRing->getNumPoints()-1);            point1.y = poRing->getY(poRing->getNumPoints()-1);            for(i=0; i < poRing->getNumPoints(); i++)             {                point2.x = poRing->getX(i);                point2.y = poRing->getY(i);                        if(EDGE_CHECK(point1.y, y, point2.y) == CLIP_MIDDLE)                 {                    if(point1.y == point2.y)                        continue; /* ignore horizontal edges */                    else                        slope = (point2.x - point1.x) / (point2.y - point1.y);                              x = point1.x + (y - point1.y)*slope;                    xintersect[nfound++] = x;                } /* End of checking this edge */                        point1 = point2;  /* Go on to next edge */            }        } /* Finished the scanline */            /* First, sort the intersections */        do         {            wrong_order = 0;            for(i=0; i < nfound-1; i++)             {                if(xintersect[i] > xintersect[i+1])                 {                    wrong_order = 1;                    SWAP(xintersect[i], xintersect[i+1], temp);                }            }        } while(wrong_order);            /* Great, now find longest span */        point1.y = point2.y = y;        for(i=0; i < nfound; i += 2)         {            point1.x = xintersect[i];            point2.x = xintersect[i+1];            /* len = length(point1, point2); */            len = ABS((point2.x - point1.x));            if(len > max_len)             {                max_len = len;                poLabelPoint->setX( (point1.x + point2.x)/2 );                poLabelPoint->setY( y );            }        }    }    free(xintersect);    /* __TODO__ Bug 673     * There seem to be some polygons for which the label is returned     * completely outside of the polygon's MBR and this messes the      * file bounds, etc.     * Until we find the source of the problem, we'll at least validate     * the label point to make sure that it overlaps the polygon MBR.     */    if( poLabelPoint->getX() < oEnv.MinX        || poLabelPoint->getY() < oEnv.MinY        || poLabelPoint->getX() > oEnv.MaxX        || poLabelPoint->getY() > oEnv.MaxY )    {        // Reset label coordinates to center of MBR, just in case        poLabelPoint->setX((oEnv.MaxX + oEnv.MinX)/2.0);        poLabelPoint->setY((oEnv.MaxY + oEnv.MinY)/2.0);        // And return an error        return OGRERR_FAILURE;    }    if(max_len > 0)        return OGRERR_NONE;    else        return OGRERR_FAILURE;}/********************************************************************** *                   OGRGetCentroid() * * Calculate polygon gravity center. *  * Returns OGRERR_NONE if it succeeds or OGRERR_FAILURE otherwise. * * Adapted version of get_centroid() from MapServer's mapprimitive.c **********************************************************************/int OGRGetCentroid(OGRPolygon *poPoly, OGRPoint *poCentroid){    int i,j;    double cent_weight_x=0.0, cent_weight_y=0.0;    double len, total_len=0;    for(i=0; i<OGR_NUM_RINGS(poPoly); i++)     {        double x1, y1, x2, y2;        OGRLinearRing *poRing = OGR_GET_RING(poPoly, i);        x2 = poRing->getX(0);        y2 = poRing->getY(0);        for(j=1; j<poRing->getNumPoints(); j++)         {            x1 = x2;            y1 = y2;            x2 = poRing->getX(j);            y2 = poRing->getY(j);            len = sqrt( pow((x2-x1),2) + pow((y2-y1),2) );            cent_weight_x += len * ((x1 + x2)/2.0);            cent_weight_y += len * ((y1 + y2)/2.0);            total_len += len;        }    }    if(total_len == 0)        return(OGRERR_FAILURE);    poCentroid->setX( cent_weight_x / total_len );    poCentroid->setY( cent_weight_y / total_len );      return OGRERR_NONE;}/********************************************************************** *                   OGRPolylineCenterPoint() * * Return the center point of a polyline. * * In MapInfo, for a simple or multiple polyline (pline), the center point  * in the object definition is supposed to be either the center point of  * the pline or the first section of a multiple pline (if an odd number of  * points in the pline or first section), or the midway point between the  * two central points (if an even number of points involved).  * * Returns OGRERR_NONE if it succeeds or OGRERR_FAILURE otherwise. **********************************************************************/int OGRPolylineCenterPoint(OGRLineString *poLine, OGRPoint *poLabelPoint){    if (poLine == NULL || poLine->getNumPoints() < 2)        return OGRERR_FAILURE;    if (poLine->getNumPoints() % 2 == 0)    {        // Return the midway between the 2 center points        int i = poLine->getNumPoints()/2;        poLabelPoint->setX( (poLine->getX(i-1) + poLine->getX(i))/2.0 );        poLabelPoint->setY( (poLine->getY(i-1) + poLine->getY(i))/2.0 );    }    else    {        // Return the center point        poLine->getPoint(poLine->getNumPoints()/2, poLabelPoint);    }        return OGRERR_NONE;}/********************************************************************** *                   OGRPolylineLabelPoint() * * Generate a label point on a polyline: The center of the longest segment. * * Returns OGRERR_NONE if it succeeds or OGRERR_FAILURE otherwise. **********************************************************************/int OGRPolylineLabelPoint(OGRLineString *poLine, OGRPoint *poLabelPoint){    double      segment_length, max_segment_length = 0.0;    double      x1, y1, x2, y2;    if (poLine == NULL || poLine->getNumPoints() < 2)        return OGRERR_FAILURE;    max_segment_length = -1.0;    x2 = poLine->getX(0);    y2 = poLine->getY(0);    for(int i=1; i<poLine->getNumPoints(); i++)     {        x1 = x2;        y1 = y2;        x2 = poLine->getX(i);        y2 = poLine->getY(i);        segment_length = pow((x2-x1),2) + pow((y2-y1),2);        if (segment_length > max_segment_length)        {            max_segment_length = segment_length;            poLabelPoint->setX( (x1 + x2)/2.0 );            poLabelPoint->setY( (y1 + y2)/2.0 );        }    }        return OGRERR_NONE;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -