Example #1
1
wxPoint2DDouble ViewPort::GetDoublePixFromLL( double lat, double lon )
{
    double easting = 0;
    double northing = 0;
    double xlon = lon;

    /*  Make sure lon and lon0 are same phase */
    if( xlon * clon < 0. ) {
        if( xlon < 0. ) xlon += 360.;
        else
            xlon -= 360.;
    }

    if( fabs( xlon - clon ) > 180. ) {
        if( xlon > clon ) xlon -= 360.;
        else
            xlon += 360.;
    }

    // update cache of trig functions used for projections
    if(clat != lat0_cache) {
        lat0_cache = clat;
        switch( m_projection_type ) {
        case PROJECTION_MERCATOR:
            cache0 = toSMcache_y30(clat);
            break;
        case PROJECTION_POLAR:
            cache0 = toPOLARcache_e(clat);
            break;
        case PROJECTION_ORTHOGRAPHIC:
        case PROJECTION_STEREOGRAPHIC:
        case PROJECTION_GNOMONIC:
            cache_phi0(clat, &cache0, &cache1);
            break;
        }
    }

    switch( m_projection_type ) {
    case PROJECTION_MERCATOR:
#if 0
        toSM( lat, xlon, clat, clon, &easting, &northing );
#else
        toSMcache( lat, xlon, cache0, clon, &easting, &northing );
#endif
        break;

    case PROJECTION_TRANSVERSE_MERCATOR:
        //    We calculate northings as referenced to the equator
        //    And eastings as though the projection point is midscreen.

        double tmeasting, tmnorthing;
        double tmceasting, tmcnorthing;
        toTM( clat, clon, 0., clon, &tmceasting, &tmcnorthing );
        toTM( lat, xlon, 0., clon, &tmeasting, &tmnorthing );

        northing = tmnorthing - tmcnorthing;
        easting = tmeasting - tmceasting;
        break;

    case PROJECTION_POLYCONIC:

        //    We calculate northings as referenced to the equator
        //    And eastings as though the projection point is midscreen.
        double pceasting, pcnorthing;
        toPOLY( clat, clon, 0., clon, &pceasting, &pcnorthing );

        double peasting, pnorthing;
        toPOLY( lat, xlon, 0., clon, &peasting, &pnorthing );

        easting = peasting;
        northing = pnorthing - pcnorthing;
        break;

    case PROJECTION_ORTHOGRAPHIC:
        toORTHO( lat, xlon, cache0, cache1, clon, &easting, &northing );
        break;

    case PROJECTION_POLAR:
        toPOLAR( lat, xlon, cache0, clat, clon, &easting, &northing );
        break;

    case PROJECTION_STEREOGRAPHIC:
        toSTEREO( lat, xlon, cache0, cache1, clon, &easting, &northing );
        break;

    case PROJECTION_GNOMONIC:
        toGNO( lat, xlon, cache0, cache1, clon, &easting, &northing );
        break;

    case PROJECTION_EQUIRECTANGULAR:
        toEQUIRECT( lat, xlon, clat, clon, &easting, &northing );
        break;

    default:
        printf("unhandled projection\n");
    }

    if( !wxFinite(easting) || !wxFinite(northing) )
        return wxPoint2DDouble( easting, northing );

    double epix = easting * view_scale_ppm;
    double npix = northing * view_scale_ppm;
    double dxr = epix;
    double dyr = npix;

    //    Apply VP Rotation
    double angle = rotation;

    if( angle ) {
        dxr = epix * cos( angle ) + npix * sin( angle );
        dyr = npix * cos( angle ) - epix * sin( angle );
    }

    return wxPoint2DDouble(( pix_width / 2.0 ) + dxr, ( pix_height / 2.0 ) - dyr);
}
Example #2
0
bool ODSelect::IsSegmentSelected( float a, float b, float c, float d, float slat, float slon )
{
    double adder = 0.;

    if( ( c * d ) < 0. ) {
        //    Arrange for points to be increasing longitude, c to d
        double dist, brg;
        DistanceBearingMercator_Plugin( a, c, b, d, &brg, &dist );
        if( brg < 180. )             // swap points?
                {
            double tmp;
            tmp = c;
            c = d;
            d = tmp;
            tmp = a;
            a = b;
            b = tmp;
        }
        if( d < 0. )     // idl?
                {
            d += 360.;
            if( slon < 0. ) adder = 360.;
        }
    }

//    As a course test, use segment bounding box test
    if( ( slat >= ( fmin ( a,b ) - selectRadius ) ) && ( slat <= ( fmax ( a,b ) + selectRadius ) )
            && ( ( slon + adder ) >= ( fmin ( c,d ) - selectRadius ) )
            && ( ( slon + adder ) <= ( fmax ( c,d ) + selectRadius ) ) ) {
        //    Use vectors to do hit test....
        ODvector2D va, vb, vn;

        //    Assuming a Mercator projection
        double ap, cp;
        toSM( a, c, 0., 0., &cp, &ap );
        double bp, dp;
        toSM( b, d, 0., 0., &dp, &bp );
        double slatp, slonp;
        toSM( slat, slon + adder, 0., 0., &slonp, &slatp );

        va.x = slonp - cp;
        va.y = slatp - ap;
        vb.x = dp - cp;
        vb.y = bp - ap;

        double delta = vGetLengthOfNormal( &va, &vb, &vn );
        if( fabs( delta ) < ( selectRadius * 1852 * 60 ) ) return true;
    }
    return false;
}
Example #3
0
//      Build PolyTessGeo Object from OGR Polygon
//      Using OpenGL/GLU tesselator
int PolyTessGeo::PolyTessGeoGL(OGRPolygon *poly, bool bSENC_SM, double ref_lat, double ref_lon)
{
#ifdef ocpnUSE_GL
    
    int iir, ip;
    int *cntr;
    GLdouble *geoPt;

    wxString    sout;
    wxString    sout1;
    wxString    stemp;

    //  Make a quick sanity check of the polygon coherence
    bool b_ok = true;
    OGRLineString *tls = poly->getExteriorRing();
    if(!tls) {
        b_ok = false;
    }
    else {
        int tnpta  = poly->getExteriorRing()->getNumPoints();
        if(tnpta < 3 )
            b_ok = false;
    }

    
    for( iir=0 ; iir < poly->getNumInteriorRings() ; iir++)
    {
        int tnptr = poly->getInteriorRing(iir)->getNumPoints();
        if( tnptr < 3 )
            b_ok = false;
    }
    
    if( !b_ok )
        return ERROR_BAD_OGRPOLY;
    

#ifdef __WXMSW__
//  If using the OpenGL dlls provided with Windows,
//  load the dll and establish addresses of the entry points needed

#ifdef USE_GLU_DLL

    if(!s_glu_dll_ready)
    {


        s_hGLU_DLL = LoadLibrary("glu32.dll");
        if (s_hGLU_DLL != NULL)
        {
            s_lpfnTessProperty = (LPFNDLLTESSPROPERTY)GetProcAddress(s_hGLU_DLL,"gluTessProperty");
            s_lpfnNewTess = (LPFNDLLNEWTESS)GetProcAddress(s_hGLU_DLL, "gluNewTess");
            s_lpfnTessBeginContour = (LPFNDLLTESSBEGINCONTOUR)GetProcAddress(s_hGLU_DLL, "gluTessBeginContour");
            s_lpfnTessEndContour = (LPFNDLLTESSENDCONTOUR)GetProcAddress(s_hGLU_DLL, "gluTessEndContour");
            s_lpfnTessBeginPolygon = (LPFNDLLTESSBEGINPOLYGON)GetProcAddress(s_hGLU_DLL, "gluTessBeginPolygon");
            s_lpfnTessEndPolygon = (LPFNDLLTESSENDPOLYGON)GetProcAddress(s_hGLU_DLL, "gluTessEndPolygon");
            s_lpfnDeleteTess = (LPFNDLLDELETETESS)GetProcAddress(s_hGLU_DLL, "gluDeleteTess");
            s_lpfnTessVertex = (LPFNDLLTESSVERTEX)GetProcAddress(s_hGLU_DLL, "gluTessVertex");
            s_lpfnTessCallback = (LPFNDLLTESSCALLBACK)GetProcAddress(s_hGLU_DLL, "gluTessCallback");

            s_glu_dll_ready = true;
        }
        else
        {
            return ERROR_NO_DLL;
        }
    }

#endif
#endif


    //  Allocate a work buffer, which will be grown as needed
#define NINIT_BUFFER_LEN 10000
    s_pwork_buf = (GLdouble *)malloc(NINIT_BUFFER_LEN * 2 * sizeof(GLdouble));
    s_buf_len = NINIT_BUFFER_LEN * 2;
    s_buf_idx = 0;

      //    Create an array to hold pointers to allocated vertices created by "combine" callback,
      //    so that they may be deleted after tesselation.
    s_pCombineVertexArray = new wxArrayPtrVoid;

    //  Create tesselator
    GLUtessobj = gluNewTess();

    //  Register the callbacks
    gluTessCallback(GLUtessobj, GLU_TESS_BEGIN,   (GLvoid (__CALL_CONVENTION *) ())&beginCallback);
    gluTessCallback(GLUtessobj, GLU_TESS_BEGIN,   (GLvoid (__CALL_CONVENTION *) ())&beginCallback);
    gluTessCallback(GLUtessobj, GLU_TESS_VERTEX,  (GLvoid (__CALL_CONVENTION *) ())&vertexCallback);
    gluTessCallback(GLUtessobj, GLU_TESS_END,     (GLvoid (__CALL_CONVENTION *) ())&endCallback);
    gluTessCallback(GLUtessobj, GLU_TESS_COMBINE, (GLvoid (__CALL_CONVENTION *) ())&combineCallback);

//    gluTessCallback(GLUtessobj, GLU_TESS_ERROR,   (GLvoid (__CALL_CONVENTION *) ())&errorCallback);

//    glShadeModel(GL_SMOOTH);
    gluTessProperty(GLUtessobj, GLU_TESS_WINDING_RULE,
                    GLU_TESS_WINDING_POSITIVE );

    //  gluTess algorithm internally selects vertically oriented triangle strips and fans.
    //  This orientation is not optimal for conventional memory-mapped raster display shape filling.
    //  We can "fool" the algorithm by interchanging the x and y vertex values passed to gluTessVertex
    //  and then reverting x and y on the resulting vertexCallbacks.
    //  In this implementation, we will explicitely set the preferred orientation.

    //Set the preferred orientation
    tess_orient = TESS_HORZ;                    // prefer horizontal tristrips



//    PolyGeo BBox as lat/lon
    OGREnvelope Envelope;
    poly->getEnvelope(&Envelope);
    xmin = Envelope.MinX;
    ymin = Envelope.MinY;
    xmax = Envelope.MaxX;
    ymax = Envelope.MaxY;


//      Get total number of contours
    m_ncnt = 1;                         // always exterior ring
    int nint = poly->getNumInteriorRings();  // interior rings
    m_ncnt += nint;


//      Allocate cntr array
    cntr = (int *)malloc(m_ncnt * sizeof(int));


//      Get total number of points(vertices)
    int npta  = poly->getExteriorRing()->getNumPoints();
    cntr[0] = npta;
    npta += 2;                            // fluff

    for( iir=0 ; iir < nint ; iir++)
    {
        int nptr = poly->getInteriorRing(iir)->getNumPoints();
        cntr[iir+1] = nptr;

        npta += nptr + 2;
    }

//    printf("pPoly npta: %d\n", npta);

    geoPt = (GLdouble *)malloc((npta) * 3 * sizeof(GLdouble));     // vertex array



   //  Grow the work buffer if necessary

    if((npta * 4) > s_buf_len)
    {
        s_pwork_buf = (GLdouble *)realloc(s_pwork_buf, npta * 4 * sizeof(GLdouble));
        s_buf_len = npta * 4;
    }


//  Define the polygon
    gluTessBeginPolygon(GLUtessobj, NULL);


//      Create input structures

//    Exterior Ring
    int npte  = poly->getExteriorRing()->getNumPoints();
    cntr[0] = npte;

    GLdouble *ppt = geoPt;


//  Check and account for winding direction of ring
    bool cw = !(poly->getExteriorRing()->isClockwise() == 0);

    double x0, y0, x, y;
    OGRPoint p;

    if(cw)
    {
        poly->getExteriorRing()->getPoint(0, &p);
        x0 = p.getX();
        y0 = p.getY();
    }
    else
    {
        poly->getExteriorRing()->getPoint(npte-1, &p);
        x0 = p.getX();
        y0 = p.getY();
    }

    //  Transcribe contour to an array of doubles, with duplicates eliminated
    double *DPbuffer = (double *)malloc(npte * 2 * sizeof(double));
    double *DPrun = DPbuffer;
    int nPoints = npte;
    
    for(ip = 0 ; ip < npte ; ip++)
    {
        int pidx;
        if(cw)
            pidx = npte - ip - 1;
    
        else
            pidx = ip;
    
        poly->getExteriorRing()->getPoint(pidx, &p);
        x = p.getX();
        y = p.getY();
    
        if(  ((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS)))
        {
            GLdouble *ppt_temp = ppt;
            if(tess_orient == TESS_VERT)
            {
                *DPrun++ = x;
                *DPrun++ = y;
            }
            else
            {
                *DPrun++ = y;
                *DPrun++ = x;
            }
        
            x0 = x;
            y0 = y;
        }
        else
            nPoints--;
    
    }

 
    if(nPoints > 5 && (m_LOD_meters > .01)){
        index_keep.Clear();
        index_keep.Add(0);
        index_keep.Add(nPoints-1);
        index_keep.Add(1);
        index_keep.Add(nPoints-2);
        
        DouglasPeucker(DPbuffer, 1, nPoints-2, m_LOD_meters/(1852 * 60), &index_keep);
//        printf("DP Reduction: %d/%d\n", index_keep.GetCount(), nPoints);
        
        g_keep += index_keep.GetCount();
        g_orig += nPoints;
//        printf("...................Running: %g\n", (double)g_keep/g_orig);
    }
    else {
        index_keep.Clear();
        for(int i = 0 ; i < nPoints ; i++)
            index_keep.Add(i);
    }
    
    cntr[0] = index_keep.GetCount();
 
    
    // Mark the keepers by adding a simple constant to X
    for(unsigned int i=0 ; i < index_keep.GetCount() ; i++){
        int k = index_keep.Item(i);
        DPbuffer[2*k] += 2000.;
    }

    

    //  Declare the gluContour and copy the points
    gluTessBeginContour(GLUtessobj);
    
    DPrun = DPbuffer;
    for(ip = 0 ; ip < nPoints ; ip++)
    {
        x = *DPrun++;
        y = *DPrun++;
        
        if(x > 1000.){
            
            GLdouble *ppt_top = ppt;
            *ppt++ = x-2000;
            *ppt++ = y;
            *ppt++ = 0;
            
            gluTessVertex( GLUtessobj, ppt_top, ppt_top ) ;
        }
    }
    
    gluTessEndContour(GLUtessobj);
    
    free(DPbuffer);    
    
  
//  Now the interior contours
    for(iir=0 ; iir < nint ; iir++)
    {
        gluTessBeginContour(GLUtessobj);

        int npti = poly->getInteriorRing(iir)->getNumPoints();

      //  Check and account for winding direction of ring
        bool cw = !(poly->getInteriorRing(iir)->isClockwise() == 0);

        if(!cw)
        {
            poly->getInteriorRing(iir)->getPoint(0, &p);
            x0 = p.getX();
            y0 = p.getY();
        }
        else
        {
            poly->getInteriorRing(iir)->getPoint(npti-1, &p);
            x0 = p.getX();
            y0 = p.getY();
        }

//  Transcribe points to vertex array, in proper order with no duplicates
//   also, accounting for tess_orient
        for(int ip = 0 ; ip < npti ; ip++)
        {
            OGRPoint p;
            int pidx;
            if(!cw)                               // interior contours must be cw
                pidx = npti - ip - 1;
            else
                pidx = ip;

            poly->getInteriorRing(iir)->getPoint(pidx, &p);
            x = p.getX();
            y = p.getY();

            if((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS))
            {
                GLdouble *ppt_temp = ppt;
                if(tess_orient == TESS_VERT)
                {
                    *ppt++ = x;
                    *ppt++ = y;
                }
                else
                {
                    *ppt++ = y;
                    *ppt++ = x;
                }
                *ppt++ = 0.0;

                gluTessVertex( GLUtessobj, ppt_temp, ppt_temp ) ;

//       printf("tess from Poly, internal vertex %d %g %g\n", ip, x, y);

            }
            else
                cntr[iir+1]--;

            x0 = x;
            y0 = y;

        }

        gluTessEndContour(GLUtessobj);
    }

    //  Store some SM conversion data in static store,
    //  for callback access
    s_ref_lat = ref_lat;
    s_ref_lon = ref_lon;
    s_bSENC_SM = bSENC_SM;

    s_bmerc_transform = false;

    //      Ready to kick off the tesselator

    s_pTPG_Last = NULL;
    s_pTPG_Head = NULL;

    s_nvmax = 0;

    gluTessEndPolygon(GLUtessobj);          // here it goes

    m_nvertex_max = s_nvmax;               // record largest vertex count, updates in callback


    //  Tesselation all done, so...

    //  Create the data structures

    m_ppg_head = new PolyTriGroup;
    m_ppg_head->m_bSMSENC = s_bSENC_SM;

    m_ppg_head->nContours = m_ncnt;

    m_ppg_head->pn_vertex = cntr;             // pointer to array of poly vertex counts
    m_ppg_head->data_type = DATA_TYPE_DOUBLE;
    

//  Transcribe the raw geometry buffer
//  Converting to float as we go, and
//  allowing for tess_orient
//  Also, convert to SM if requested

// Recalculate the size of the geometry buffer
    int nptfinal = cntr[0] + 2;
    for(int i=0 ; i < nint ; i++)
        nptfinal += cntr[i+1] + 2;
    
    //  No longer need the full geometry in the SENC,
    nptfinal = 1;
    
    m_nwkb = (nptfinal + 1) * 2 * sizeof(float);
    m_ppg_head->pgroup_geom = (float *)calloc(sizeof(float), (nptfinal + 1) * 2);
    float *vro = m_ppg_head->pgroup_geom;
    ppt = geoPt;
    float tx,ty;

    for(ip = 0 ; ip < nptfinal ; ip++)
    {
        if(TESS_HORZ == tess_orient)
        {
            ty = *ppt++;
            tx = *ppt++;
        }
        else
        {
            tx = *ppt++;
            ty = *ppt++;
        }

        if(bSENC_SM)
        {
            //  Calculate SM from chart common reference point
            double easting, northing;
            toSM(ty, tx, ref_lat, ref_lon, &easting, &northing);
            *vro++ = easting;              // x
            *vro++ = northing;             // y
        }
        else
        {
            *vro++ = tx;                  // lon
            *vro++ = ty;                  // lat
        }

        ppt++;                      // skip z
    }

    m_ppg_head->tri_prim_head = s_pTPG_Head;         // head of linked list of TriPrims


    //  Convert the Triangle vertex arrays into a single memory allocation of floats
    //  to reduce SENC size and enable efficient access later
    
    //  First calculate the total byte size
    int total_byte_size = 2 * sizeof(float);
    TriPrim *p_tp = m_ppg_head->tri_prim_head;
    while( p_tp ) {
        total_byte_size += p_tp->nVert * 2 * sizeof(float);
        p_tp = p_tp->p_next; // pick up the next in chain
    }
    
    float *vbuf = (float *)malloc(total_byte_size);
    p_tp = m_ppg_head->tri_prim_head;
    float *p_run = vbuf;
    while( p_tp ) {
        float *pfbuf = p_run;
        GLdouble *pdouble_buf = (GLdouble *)p_tp->p_vertex;
        
        for( int i=0 ; i < p_tp->nVert * 2 ; ++i){
            float x = (float)( *((GLdouble *)pdouble_buf) );
            pdouble_buf++;
            *p_run++ = x;
        }
        
        free(p_tp->p_vertex);
        p_tp->p_vertex = (double *)pfbuf;
        p_tp = p_tp->p_next; // pick up the next in chain
    }
    m_ppg_head->bsingle_alloc = true;
    m_ppg_head->single_buffer = (unsigned char *)vbuf;
    m_ppg_head->single_buffer_size = total_byte_size;
    m_ppg_head->data_type = DATA_TYPE_FLOAT;
    
    
    
    
    
    
    gluDeleteTess(GLUtessobj);

    free( s_pwork_buf );
    s_pwork_buf = NULL;

    free (geoPt);

    //      Free up any "Combine" vertices created
    for(unsigned int i = 0; i < s_pCombineVertexArray->GetCount() ; i++)
          free (s_pCombineVertexArray->Item(i));
    delete s_pCombineVertexArray;

    m_bOK = true;

#endif          //    #ifdef ocpnUSE_GL
    
    return 0;
}
Example #4
0
wxPoint2DDouble ViewPort::GetDoublePixFromLL( double lat, double lon )
{
    double easting, northing;
    double xlon = lon;

    /*  Make sure lon and lon0 are same phase */
    if( xlon * clon < 0. ) {
        if( xlon < 0. ) xlon += 360.;
        else
            xlon -= 360.;
    }

    if( fabs( xlon - clon ) > 180. ) {
        if( xlon > clon ) xlon -= 360.;
        else
            xlon += 360.;
    }

    if( PROJECTION_TRANSVERSE_MERCATOR == m_projection_type ) {
        //    We calculate northings as referenced to the equator
        //    And eastings as though the projection point is midscreen.

        double tmeasting, tmnorthing;
        double tmceasting, tmcnorthing;
        toTM( clat, clon, 0., clon, &tmceasting, &tmcnorthing );
        toTM( lat, xlon, 0., clon, &tmeasting, &tmnorthing );

        northing = tmnorthing - tmcnorthing;
        easting = tmeasting - tmceasting;
    } else if( PROJECTION_POLYCONIC == m_projection_type ) {

        //    We calculate northings as referenced to the equator
        //    And eastings as though the projection point is midscreen.
        double pceasting, pcnorthing;
        toPOLY( clat, clon, 0., clon, &pceasting, &pcnorthing );

        double peasting, pnorthing;
        toPOLY( lat, xlon, 0., clon, &peasting, &pnorthing );

        easting = peasting;
        northing = pnorthing - pcnorthing;
    }

    else {
#if 0
        toSM( lat, xlon, clat, clon, &easting, &northing );
#else
        if(clat != toSM_lat0_cache) {
            toSM_lat0_cache = clat;
            toSM_y30_cache = toSMcache_y30(clat);
        }
        toSMcache( lat, xlon, toSM_y30_cache, clon, &easting, &northing );
#endif
    }

    if( !wxFinite(easting) || !wxFinite(northing) ) return wxPoint( 0, 0 );

    double epix = easting * view_scale_ppm;
    double npix = northing * view_scale_ppm;
    double dxr = epix;
    double dyr = npix;

    //    Apply VP Rotation
    double angle = rotation;
    if(!g_bskew_comp)
        angle += skew;

    if( angle ) {
        dxr = epix * cos( angle ) + npix * sin( angle );
        dyr = npix * cos( angle ) - epix * sin( angle );
    }

    return wxPoint2DDouble(( pix_width / 2 ) + dxr, ( pix_height / 2 ) - dyr);
}
Example #5
0
void __CALL_CONVENTION endCallback(void)
{
    //      Create a TriPrim

    char buf[40];

    if(s_nvcall > s_nvmax)                            // keep track of largest number of triangle vertices
          s_nvmax = s_nvcall;

    switch(s_gltri_type)
    {
        case GL_TRIANGLE_FAN:
        case GL_TRIANGLE_STRIP:
        case GL_TRIANGLES:
        {
            TriPrim *pTPG = new TriPrim;
            if(NULL == s_pTPG_Last)
            {
                s_pTPG_Head = pTPG;
                s_pTPG_Last = pTPG;
            }
            else
            {
                s_pTPG_Last->p_next = pTPG;
                s_pTPG_Last = pTPG;
            }

            pTPG->p_next = NULL;
            pTPG->type = s_gltri_type;
            pTPG->nVert = s_nvcall;

        //  Calculate bounding box
            float sxmax = -1000;                   // this poly BBox
            float sxmin = 1000;
            float symax = -90;
            float symin = 90;

            GLdouble *pvr = s_pwork_buf;
            for(int iv=0 ; iv < s_nvcall ; iv++)
            {
                GLdouble xd, yd;
                xd = *pvr++;
                yd = *pvr++;

                if(s_bmerc_transform)
                {
                      double valx = ( xd * s_transform_x_rate ) + s_transform_x_origin;
                      double valy = ( yd * s_transform_y_rate ) + s_transform_y_origin;

                      //    Convert to lat/lon
                      double lat = ( 2.0 * atan ( exp ( valy/CM93_semimajor_axis_meters ) ) - PI/2. ) / DEGREE;
                      double lon = ( valx / ( DEGREE * CM93_semimajor_axis_meters ) );

                      sxmax = wxMax(lon, sxmax);
                      sxmin = wxMin(lon, sxmin);
                      symax = wxMax(lat, symax);
                      symin = wxMin(lat, symin);
                }
                else
                {
                      sxmax = wxMax(xd, sxmax);
                      sxmin = wxMin(xd, sxmin);
                      symax = wxMax(yd, symax);
                      symin = wxMin(yd, symin);
                }
            }

            pTPG->tri_box.Set(symin, sxmin, symax, sxmax);

            //  Transcribe this geometry to TriPrim, converting to SM if called for

            if(s_bSENC_SM)
            {
                GLdouble *pds = s_pwork_buf;
                pTPG->p_vertex = (double *)malloc(s_nvcall * 2 * sizeof(double));
                GLdouble *pdd = (GLdouble*)pTPG->p_vertex;

                for(int ip = 0 ; ip < s_nvcall ; ip++)
                {
                    double dlon = *pds++;
                    double dlat = *pds++;

                    double easting, northing;
                    toSM(dlat, dlon, s_ref_lat, s_ref_lon, &easting, &northing);
                    *pdd++ = easting;
                    *pdd++ = northing;
                }
            }
            else
            {
                pTPG->p_vertex = (double *)malloc(s_nvcall * 2 * sizeof(double));
                memcpy(pTPG->p_vertex, s_pwork_buf, s_nvcall * 2 * sizeof(double));
            }


            break;
        }
        default:
        {
            sprintf(buf, "....begin Callback  unknown\n");
            break;
        }
    }
}
Example #6
0
int PolyTessGeo::BuildTess(void)
{
    //  Setup the tesselator
    
    TESSalloc ma;
    TESStesselator* tess = 0;
    const int nvp = 3;
//    unsigned char* vflags = 0;
#ifdef USE_POOL
    struct MemPool pool;
    unsigned char mem[4024*1024];
//    int nvflags = 0;
#else
    int allocated = 0;
    double t0 = 0, t1 = 0;
#endif

#ifdef USE_POOL

    pool.size = 0;
    pool.cap = sizeof(mem);
    pool.buf = mem;
    memset(&ma, 0, sizeof(ma));
    ma.memalloc = poolAlloc;
    ma.memfree = poolFree;
    ma.userData = (void*)&pool;
    ma.extraVertices = 256; // realloc not provided, allow 256 extra vertices.

#else
 
    memset(&ma, 0, sizeof(ma));
    ma.memalloc = stdAlloc;
    ma.memfree = stdFree;
    ma.userData = (void*)&allocated;
    ma.extraVertices = 256; // realloc not provided, allow 256 extra vertices.
#endif

    tess = tessNewTess(&ma);
    if (!tess)
        return -1;

    //tessSetOption(tess, TESS_CONSTRAINED_DELAUNAY_TRIANGULATION, 1);

    
    //  Create the contour vertex arrays
    
      int iir, ip;

//      Get max number number of points(vertices) in any contour
      int npta  = m_cntr[0];
      npta += 2;                            // fluff

      for( iir=0 ; iir < m_ncnt-1 ; iir++){
            int nptr = m_cntr[iir+1];
            npta = wxMax(npta, nptr); 
      }


      TESSreal *geoPt = (TESSreal *)malloc((npta) * 2 * sizeof(TESSreal));     // tess input vertex array
      TESSreal *ppt = geoPt;


//      Create input structures

//    Exterior Ring
      int npte = m_cntr[0];
      unsigned int ptValid = npte;

//  Check and account for winding direction of ring


      double x0, y0, x, y;
      OGRPoint p;

      wxPoint2DDouble *pp = (wxPoint2DDouble *)m_vertexPtrArray[0];
      bool cw = isRingClockwise(pp, m_cntr[0]);
      
      //pp++;       // skip 0?

      if(cw)
      {
            x0 = pp->m_x;
            y0 = pp->m_y;
      }
      else
      {
            x0 = pp[npte-1].m_x;
            y0 = pp[npte-1].m_y;
      }



//  Transcribe points to vertex array, in proper order with no duplicates
//   also, accounting for tess_orient
      for(ip = 0 ; ip < npte ; ip++)
      {
            int pidx;
            if(cw)
                  pidx = npte - ip - 1;

            else
                  pidx = ip;

            x = pp[pidx].m_x;
            y = pp[pidx].m_y;

            if((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS))
            {
                  if(m_tess_orient == TESS_VERT)
                  {
                        *ppt++ = x;
                        *ppt++ = y;
                  }
                  else
                  {
                        *ppt++ = y;
                        *ppt++ = x;
                  }
            }
            else
                  ptValid--;

            x0 = x;
            y0 = y;
      }

      
      //  Apply LOD reduction
    int beforeLOD = ptValid;
    int afterLOD = beforeLOD;
   
    std::vector<bool> bool_keep;
    if(ptValid > 5 && (m_LOD_meters > .01)){
        
        for(unsigned int i = 0 ; i < ptValid ; i++)
            bool_keep.push_back(false);

        // Keep a few key points
        bool_keep[0] = true;
        bool_keep[1] = true;
        bool_keep[ptValid-1] = true;
        bool_keep[ptValid-2] = true;
        
        DouglasPeuckerFI(geoPt, 1, ptValid-2, m_LOD_meters, bool_keep);
            
        // Create a new buffer
        float *LOD_result = (float *)malloc((npte) * 2 * sizeof(float));     
        float *plod = LOD_result;
        int kept_LOD =0;
        
        for(unsigned int i=0 ; i < ptValid ; i++){
            if(bool_keep[i]){
                float x = geoPt[i*2];
                float y = geoPt[(i*2) + 1];
                *plod++ = x;
                *plod++ = y;
                kept_LOD++;
            }
        }

        beforeLOD = ptValid;
        afterLOD = kept_LOD;
    
        tessAddContour(tess, 2, LOD_result, sizeof(float)*2, kept_LOD);
        
        free(LOD_result);
    }
    else {
        tessAddContour(tess, 2, geoPt, sizeof(float)*2, ptValid);
    }
    
    

#if 1
//  Now the interior contours
      for(iir=0; iir < m_ncnt-1; iir++)
      {
            ppt = geoPt;
            wxPoint2DDouble *pp = (wxPoint2DDouble *)m_vertexPtrArray[iir + 1];

            int npti  = m_cntr[iir+1];
            ptValid = npti;
            
      //  Check and account for winding direction of ring
            bool cw = isRingClockwise(pp, m_cntr[iir+1]);

            if(!cw)
            {
                  x0 = pp[0].m_x;
                  y0 = pp[0].m_y;
            }
            else
            {
                  x0 = pp[npti-1].m_x;
                  y0 = pp[npti-1].m_y;
            }

//  Transcribe points to vertex array, in proper order with no duplicates
//   also, accounting for tess_orient
            for(int ip = 0 ; ip < npti ; ip++)
            {
                  OGRPoint p;
                  int pidx;
                  if(!cw)                               // interior contours must be cw
                        pidx = npti - ip - 1;
                  else
                        pidx = ip;


                  x = pp[pidx].m_x;
                  y = pp[pidx].m_y;

                  if((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS))
                  {
                        if(m_tess_orient == TESS_VERT)
                        {
                              *ppt++ = x;
                              *ppt++ = y;
                        }
                        else
                        {
                              *ppt++ = y;
                              *ppt++ = x;
                        }
                  }
                  else
                        ptValid--;

                  x0 = x;
                  y0 = y;

            }
            
            tessAddContour(tess, 2, geoPt, sizeof(float)*2, ptValid);

      }
#endif


      //      Ready to kick off the tesselator

      TriPrim *pTPG_Last = NULL;
      TriPrim *pTPG_Head = NULL;

      //s_nvmax = 0;

      //OCPNStopWatchTess tt0;
      
      if (!tessTesselate(tess, TESS_WINDING_POSITIVE, TESS_POLYGONS, nvp, 2, 0))
        return -1;
      double tessTime = 0; //tt0.GetTime();


    //  Tesselation all done, so...
    //  Create the data structures
    
    //  Make a linked list of TriPrims from tess output arrays

    const TESSreal* verts = tessGetVertices(tess);
    const int* vinds = tessGetVertexIndices(tess);
    const int* elems = tessGetElements(tess);
    const int nverts = tessGetVertexCount(tess);
    int nelems = tessGetElementCount(tess);

      
    bool skip = false;
    //skip = true;
    
    double stripTime = 0;
    //tt0.Reset();

    int bytes_needed_vbo = 0;
    float *vbo = 0;
    
    if(m_bstripify && nelems && !skip){
        
         
        STRIPERCREATE sc;
        sc.DFaces                       = (udword *)elems;
        sc.NbFaces                      = nelems;
        sc.AskForWords          = false;
        sc.ConnectAllStrips     = false;
        sc.OneSided             = false;
        sc.SGIAlgorithm         = false;

       
        Striper Strip;
        Strip.Init(sc);
        
        STRIPERRESULT sr;
        Strip.Compute(sr);

        stripTime = 0; //tt0.GetTime();

/*        
        fprintf(stdout, "Number of strips: %d\n", sr.NbStrips);
        fprintf(stdout, "Number of points: %d\n", nelems);
        uword* Refs = (uword*)sr.StripRuns;
        for(udword i=0;i<sr.NbStrips;i++)
        {
                fprintf(stdout, "Strip %d:   ", i);
                udword NbRefs = sr.StripLengths[i];
                for(udword j=0;j<NbRefs;j++)
                {
                        fprintf(stdout, "%d ", *Refs++);
                }
                fprintf(stdout, "\n");
        }
*/
        // calculate and allocate the final (float) VBO-like buffer for this entire feature
        
        int *Refs = (int *)sr.StripRuns;
        for(unsigned int i=0;i<sr.NbStrips;i++){
            unsigned int NbRefs = sr.StripLengths[i];         //  vertices per strip
            bytes_needed_vbo += NbRefs * 2 * sizeof(float);
        }
        
        vbo = (float *)malloc(bytes_needed_vbo);
        float *vbo_run = vbo;
        
        for(unsigned int i=0;i<sr.NbStrips;i++){
            unsigned int NbRefs = sr.StripLengths[i];         //  vertices per strip
 
            if(NbRefs >= 3){                              // this is a valid primitive

                TriPrim *pTPG = new TriPrim;
                if(NULL == pTPG_Last){
                    pTPG_Head = pTPG;
                    pTPG_Last = pTPG;
                }
                else{
                    pTPG_Last->p_next = pTPG;
                    pTPG_Last = pTPG;
                }

                pTPG->p_next = NULL;
                pTPG->nVert = NbRefs;
            
//                pTPG->p_vertex = (double *)malloc(NbRefs * 2 * sizeof(double));
//                GLdouble *pdd = (GLdouble*)pTPG->p_vertex;

                pTPG->p_vertex = (double *)vbo_run;

            //  Preset LLBox bounding box limits
                double sxmax = -1e8;
                double sxmin = 1e8;
                double symax = -1e8;
                double symin = 1e8;

                if(NbRefs >3)
                    pTPG->type = GL_TRIANGLE_STRIP;
                else
                    pTPG->type = GL_TRIANGLES;

                // Add the first two points
                int vindex[3];
                vindex[0] = *Refs++;
                vindex[1] = *Refs++;
                unsigned int np = 2;         // for the first triangle
                    
                for(unsigned int i = 2; i < NbRefs ; i++){    
                    vindex[np] = *Refs++;
                    np++;
                    
                    for (unsigned int j = 0; j < np; ++j){
                        double yd = verts[vindex[j]*2];
                        double xd = verts[vindex[j]*2+1];
                    
                    // Calculate LLBox bounding box for each Tri-prim
                        if(m_bmerc_transform){
                            double valx = ( xd * mx_rate ) + mx_offset;
                            double valy = ( yd * my_rate ) + my_offset;
            
                                //    quickly convert to lat/lon
                            double lat = ( 2.0 * atan ( exp ( valy/CM93_semimajor_axis_meters ) ) - PI/2. ) / DEGREE;
                            double lon= ( valx / ( DEGREE * CM93_semimajor_axis_meters ) );


                            sxmax = wxMax(lon, sxmax);
                            sxmin = wxMin(lon, sxmin);
                            symax = wxMax(lat, symax);
                            symin = wxMin(lat, symin);
                        }
                        else{
                            sxmax = wxMax(xd, sxmax);
                            sxmin = wxMin(xd, sxmin);
                            symax = wxMax(yd, symax);
                            symin = wxMin(yd, symin);
                        }
                        
                    //  Append this point to TriPrim vbo

                        *vbo_run++ = (xd) + m_feature_easting;    // adjust to chart ref coordinates
                        *vbo_run++ = (yd) + m_feature_northing;
                    }               // For

                    // Compute the final LLbbox for this TriPrim chain
                    double minlat, minlon, maxlat, maxlon;
                    fromSM(sxmin, symin, m_feature_ref_lat, m_feature_ref_lon, &minlat, &minlon);
                    fromSM(sxmax, symax, m_feature_ref_lat, m_feature_ref_lon, &maxlat, &maxlon);

                    pTPG->tri_box.Set(minlat, minlon, maxlat, maxlon);

                    // set for next single point
                    np = 0;

                }
            }
            else
                Refs += sr.StripLengths[i];
           
        }                       // for strips
    }
    else{       // not stripified
        
        m_nvertex_max = nverts;               // record largest vertex count
        
        bytes_needed_vbo = nelems * nvp * 2 * sizeof(float);
        vbo = (float *)malloc(bytes_needed_vbo);
        float *vbo_run = vbo;

        for (int i = 0; i < nelems; ++i){
            const int* p = &elems[i*nvp];

            TriPrim *pTPG = new TriPrim;
            if(NULL == pTPG_Last){
                    pTPG_Head = pTPG;
                    pTPG_Last = pTPG;
            }
            else{
                    pTPG_Last->p_next = pTPG;
                    pTPG_Last = pTPG;
            }

            pTPG->p_next = NULL;
            pTPG->type = GL_TRIANGLES;
            pTPG->nVert = nvp;
            
//            pTPG->p_vertex = (double *)malloc(nvp * 2 * sizeof(double));
//            GLdouble *pdd = (GLdouble*)pTPG->p_vertex;

            pTPG->p_vertex = (double *)vbo_run;

            //  Preset LLBox bounding box limits
            double sxmax = -1e8;
            double sxmin = 1e8;
            double symax = -1e8;
            double symin = 1e8;

            for (size_t j = 0; j < nvp && p[j] != TESS_UNDEF; ++j){
                double yd = verts[p[j]*2];
                double xd = verts[p[j]*2+1];
                
                // Calculate LLBox bounding box for each Tri-prim
                if(m_bmerc_transform){
                    double valx = ( xd * mx_rate ) + mx_offset;
                    double valy = ( yd * my_rate ) + my_offset;
    
                        //    quickly convert to lat/lon
                    double lat = ( 2.0 * atan ( exp ( valy/CM93_semimajor_axis_meters ) ) - PI/2. ) / DEGREE;
                    double lon= ( valx / ( DEGREE * CM93_semimajor_axis_meters ) );


                    sxmax = wxMax(lon, sxmax);
                    sxmin = wxMin(lon, sxmin);
                    symax = wxMax(lat, symax);
                    symin = wxMin(lat, symin);
                }
                else{
                    sxmax = wxMax(xd, sxmax);
                    sxmin = wxMin(xd, sxmin);
                    symax = wxMax(yd, symax);
                    symin = wxMin(yd, symin);
                }
                
                //  Append this point to TriPrim, converting to SM if called for

                if(m_b_senc_sm){
                    double easting, northing;
                    toSM(yd, xd, m_ref_lat, m_ref_lon, &easting, &northing);
                    *vbo_run++ = easting;
                    *vbo_run++ = northing;
                }
                else{
                    *vbo_run++ = xd;
                    *vbo_run++ = yd;
                }
            }
        
        pTPG->tri_box.Set(symin, sxmin, symax, sxmax);
        }
    }           // stripify

    if(m_printStats){
        int nTri = 0;
        int nStrip = 0;
        
        TriPrim *p_tp = pTPG_Head;
        while( p_tp ) {
            if(p_tp->type == GL_TRIANGLES)
                nTri++;
            if(p_tp->type == GL_TRIANGLE_STRIP)
                nStrip++;
            
          p_tp = p_tp->p_next; // pick up the next in chain
        }
        
        if((nTri + nStrip) > 10000){
            printf("LOD:  %d/%d\n", afterLOD, beforeLOD);

            printf("Tess time(ms): %f\n", tessTime);
            printf("Strip time(ms): %f\n", stripTime);

            printf("Primitives:   Tri: %5d  Strip: %5d  Total: %5d\n", nTri, nStrip, nTri + nStrip);
            printf("\n");
        }
    }
 
   
    
      m_ppg_head = new PolyTriGroup;
      m_ppg_head->m_bSMSENC = m_b_senc_sm;

      m_ppg_head->nContours = m_ncnt;
      m_ppg_head->pn_vertex = m_cntr;             // pointer to array of poly vertex counts
      m_ppg_head->tri_prim_head = pTPG_Head;         // head of linked list of TriPrims
      //m_ppg_head->data_type = DATA_TYPE_DOUBLE;
      

//  Transcribe the raw geometry buffer
//  Converting to float as we go, and
//  allowing for tess_orient
//  Also, convert to SM if requested

      int nptfinal = npta;
      
      //  No longer need the full geometry in the SENC,
      nptfinal = 1;
      
      m_nwkb = (nptfinal +1) * 2 * sizeof(float);
      m_ppg_head->pgroup_geom = (float *)malloc(m_nwkb);
      float *vro = m_ppg_head->pgroup_geom;
      ppt = geoPt;
      float tx,ty;

      for(ip = 0 ; ip < nptfinal ; ip++)
      {
            if(TESS_HORZ == m_tess_orient)
            {
                  ty = *ppt++;
                  tx = *ppt++;
            }
            else
            {
                  tx = *ppt++;
                  ty = *ppt++;
            }

            if(m_b_senc_sm)
            {
            //  Calculate SM from chart common reference point
                  double easting, northing;
                  toSM(ty, tx, 0/*ref_lat*/, 0/*ref_lon*/, &easting, &northing);
                  *vro++ = easting;              // x
                  *vro++ = northing;             // y
            }
            else
            {
                  *vro++ = tx;                  // lon
                  *vro++ = ty;                  // lat
            }

            ppt++;                      // skip z
      }


      m_ppg_head->bsingle_alloc = true;
      m_ppg_head->single_buffer = (unsigned char *)vbo;
      m_ppg_head->single_buffer_size = bytes_needed_vbo;
      m_ppg_head->data_type = DATA_TYPE_FLOAT;
      

      free (geoPt);

      //    All allocated buffers are owned now by the m_ppg_head
      //    And will be freed on dtor of this object
 
      if (tess) tessDeleteTess(tess);

      m_bOK = true;
      

      return 0;
      

}
Example #7
0
//      Build PolyTessGeo Object from OGR Polygon
//      Using OpenGL/GLU tesselator
int PolyTessGeo::BuildTessGLU()
{
    
    unsigned int iir, ip;
    GLdouble *geoPt;


#if 0    
    //  Make a quick sanity check of the polygon coherence
    bool b_ok = true;
    OGRLineString *tls = poly->getExteriorRing();
    if(!tls) {
        b_ok = false;
    }
    else {
        int tnpta  = poly->getExteriorRing()->getNumPoints();
        if(tnpta < 3 )
            b_ok = false;
    }

    
    for( iir=0 ; iir < poly->getNumInteriorRings() ; iir++)
    {
        int tnptr = poly->getInteriorRing(iir)->getNumPoints();
        if( tnptr < 3 )
            b_ok = false;
    }
    
    if( !b_ok )
        return ERROR_BAD_OGRPOLY;
    
#endif
    


    //  Allocate a work buffer, which will be grown as needed
#define NINIT_BUFFER_LEN 10000
    m_pwork_buf = (GLdouble *)malloc(NINIT_BUFFER_LEN * 2 * sizeof(GLdouble));
    m_buf_len = NINIT_BUFFER_LEN * 2;
    m_buf_idx = 0;

      //    Create an array to hold pointers to allocated vertices created by "combine" callback,
      //    so that they may be deleted after tesselation.
    m_pCombineVertexArray = new wxArrayPtrVoid;

    //  Create tesselator
    GLUtessobj = gluNewTess();

    //  Register the callbacks
    gluTessCallback(GLUtessobj, GLU_TESS_BEGIN_DATA,   (GLvoid (*) ())&beginCallback);
    gluTessCallback(GLUtessobj, GLU_TESS_BEGIN_DATA,   (GLvoid (*) ())&beginCallback);
    gluTessCallback(GLUtessobj, GLU_TESS_VERTEX_DATA,  (GLvoid (*) ())&vertexCallback);
    gluTessCallback(GLUtessobj, GLU_TESS_END_DATA,     (GLvoid (*) ())&endCallback);
    gluTessCallback(GLUtessobj, GLU_TESS_COMBINE_DATA, (GLvoid (*) ())&combineCallback);
    gluTessCallback(GLUtessobj, GLU_TESS_ERROR_DATA,   (GLvoid (*) ())&errorCallback);

    gluTessProperty(GLUtessobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
    gluTessNormal(GLUtessobj, 0, 0, 1);

//      Get total number of points(vertices)  to build a buffer
    int npta  = 0;

    for( int i=0 ; i < m_ncnt ; i++)
        npta += m_cntr[i];


    geoPt = (GLdouble *)malloc((npta + 6) * 3 * sizeof(GLdouble));     // vertex array



   //  Grow the work buffer if necessary

    if((npta * 4) > m_buf_len)
    {
        m_pwork_buf = (GLdouble *)realloc(m_pwork_buf, npta * 4 * sizeof(GLdouble));
        m_buf_len = npta * 4;
    }


//  Define the polygon
    gluTessBeginPolygon(GLUtessobj, this);


    
    //  Check and account for winding direction of ring


      double x0, y0, x, y;
//      OGRPoint p;

      wxPoint2DDouble *pp = (wxPoint2DDouble *)m_vertexPtrArray[0];
      bool cw = !isRingClockwise(pp, m_cntr[0]);
      
      //pp++;       // skip 0?

      if(cw)
      {
            x0 = pp->m_x;
            y0 = pp->m_y;
      }
      else
      {
            x0 = pp[m_cntr[0]-1].m_x;
            y0 = pp[m_cntr[0]-1].m_y;
      }



      unsigned int ptValid = m_cntr[0];
      
//  Transcribe points to vertex array, in proper order with no duplicates
//   also, accounting for tess_orient
      GLdouble *ppt = geoPt;
      
      for(ip = 0 ; ip < (unsigned int)m_cntr[0] ; ip++)
      {
            int pidx;
            if(cw)
                  pidx = m_cntr[0] - ip - 1;

            else
                  pidx = ip;

            x = pp[pidx].m_x;
            y = pp[pidx].m_y;

            if((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS))
            {
                  if(m_tess_orient == TESS_VERT)
                  {
                        *ppt++ = x;
                        *ppt++ = y;
                        *ppt++ = 0;
                  }
                  else
                  {
                        *ppt++ = y;
                        *ppt++ = x;
                        *ppt++ = 0;
                  }
            }
            else
                  ptValid--;

            x0 = x;
            y0 = y;
      }

      //  Apply LOD reduction
    int beforeLOD = ptValid;
    int afterLOD = beforeLOD;
   
 
    if(ptValid > 20 && (m_LOD_meters > .01)) {
        std::vector<bool> bool_keep(ptValid, false);

        // Keep a few key points
        bool_keep[0] = true;
        bool_keep[1] = true;
        bool_keep[ptValid-1] = true;
        bool_keep[ptValid-2] = true;
        
        DouglasPeuckerDI(geoPt, 1, ptValid-2, m_LOD_meters, bool_keep);
            
        // Create a new buffer
        double *LOD_result = (double *)malloc((m_cntr[0]) * 3 * sizeof(double));     
        double *plod = LOD_result;
        int kept_LOD =0;
        
        for(unsigned int i=0 ; i < ptValid ; i++){
            if(bool_keep[i]){
                double x = geoPt[i*3];
                double y = geoPt[(i*3) + 1];
                *plod++ = x;
                *plod++ = y;
                *plod++ = 0;
                kept_LOD++;
            }
        }

        beforeLOD = ptValid;
        afterLOD = kept_LOD;

        // Copy the lod points back into the vertex buffer
        memcpy(geoPt, LOD_result, kept_LOD * 3 * sizeof(double));
        
        free(LOD_result);
        ptValid = kept_LOD;
    }

    //  Declare the gluContour and copy the points
    gluTessBeginContour(GLUtessobj);
    
    double *DPrun = geoPt;
    for(ip = 0 ; ip < ptValid ; ip++) {
        gluTessVertex( GLUtessobj, DPrun, DPrun ) ;
        DPrun += 3;
    }
  
    gluTessEndContour(GLUtessobj);

    //  Now the interior contours
#if 1    
    int gpIndex = m_cntr[0];
    
    for(iir=0; iir < (unsigned int)m_ncnt-1; iir++){
        
            wxPoint2DDouble *pp = (wxPoint2DDouble *)m_vertexPtrArray[iir + 1];

            int npti  = m_cntr[iir+1];
            ptValid = npti;
            
            double *ppt = &geoPt[gpIndex * 3]; // next available location in geoPT
            double *DPStart = ppt;
            
      //  Check and account for winding direction of ring
            bool cw = isRingClockwise(pp, m_cntr[iir+1]);

            if(cw)
            {
                  x0 = pp[0].m_x;
                  y0 = pp[0].m_y;
            }
            else
            {
                  x0 = pp[npti-1].m_x;
                  y0 = pp[npti-1].m_y;
            }

//  Transcribe points to vertex array, in proper order with no duplicates
//   also, accounting for tess_orient
            for(int ip = 0 ; ip < npti ; ip++)
            {
                  int pidx;
                  if(cw)                               // interior contours must be cw
                        pidx = npti - ip - 1;
                  else
                        pidx = ip;


                  x = pp[pidx].m_x;
                  y = pp[pidx].m_y;

                  if((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS))
                  {
                        if(m_tess_orient == TESS_VERT)
                        {
                              *ppt++ = x;
                              *ppt++ = y;
                              *ppt++ = 0;
                        }
                        else
                        {
                              *ppt++ = y;
                              *ppt++ = x;
                              *ppt++ = 0;
                        }
                  }
                  else
                        ptValid--;

                  x0 = x;
                  y0 = y;

            }
            
                       //  Declare the gluContour and reference the points
            gluTessBeginContour(GLUtessobj);
    
            double *DPruni = DPStart;
            for(ip = 0 ; ip < ptValid ; ip++)
            {
                gluTessVertex( GLUtessobj, DPruni, DPruni ) ;
                DPruni += 3;
            }
        
            gluTessEndContour(GLUtessobj);

            gpIndex +=  m_cntr[iir+1];
      }
#endif
        
        
        
        

    m_pTPG_Last = NULL;
    m_pTPG_Head = NULL;
    m_nvmax = 0;

    //      Ready to kick off the tesselator
    gluTessEndPolygon(GLUtessobj);          // here it goes

    m_nvertex_max = m_nvmax;               // record largest vertex count, updates in callback


    //  Tesselation all done, so...

    //  Create the data structures

    m_ppg_head = new PolyTriGroup;
    m_ppg_head->m_bSMSENC = m_b_senc_sm;

    m_ppg_head->nContours = m_ncnt;

    m_ppg_head->pn_vertex = m_cntr;             // pointer to array of poly vertex counts
    m_ppg_head->data_type = DATA_TYPE_DOUBLE;
    

//  Transcribe the raw geometry buffer
//  Converting to float as we go, and
//  allowing for tess_orient
//  Also, convert to SM if requested

// Recalculate the size of the geometry buffer
    unsigned int nptfinal = m_cntr[0] + 2;
//     for(int i=0 ; i < nint ; i++)
//         nptfinal += cntr[i+1] + 2;
    
    //  No longer need the full geometry in the SENC,
    nptfinal = 1;
    
    m_nwkb = (nptfinal + 1) * 2 * sizeof(float);
    m_ppg_head->pgroup_geom = (float *)calloc(sizeof(float), (nptfinal + 1) * 2);
    float *vro = m_ppg_head->pgroup_geom;
    ppt = geoPt;
    float tx,ty;

    for(ip = 0 ; ip < nptfinal ; ip++)
    {
        if(TESS_HORZ == m_tess_orient)
        {
            ty = *ppt++;
            tx = *ppt++;
        }
        else
        {
            tx = *ppt++;
            ty = *ppt++;
        }

        if(m_b_senc_sm)
        {
            //  Calculate SM from chart common reference point
            double easting, northing;
            toSM(ty, tx, m_ref_lat, m_ref_lon, &easting, &northing);
            *vro++ = easting;              // x
            *vro++ = northing;             // y
        }
        else
        {
            *vro++ = tx;                  // lon
            *vro++ = ty;                  // lat
        }

        ppt++;                      // skip z
    }

    m_ppg_head->tri_prim_head = m_pTPG_Head;         // head of linked list of TriPrims


    //  Convert the Triangle vertex arrays into a single memory allocation of floats
    //  to reduce SENC size and enable efficient access later
    
    //  First calculate the total byte size
    int total_byte_size = 2 * sizeof(float);
    TriPrim *p_tp = m_ppg_head->tri_prim_head;
    while( p_tp ) {
        total_byte_size += p_tp->nVert * 2 * sizeof(float);
        p_tp = p_tp->p_next; // pick up the next in chain
    }
    
    float *vbuf = (float *)malloc(total_byte_size);
    p_tp = m_ppg_head->tri_prim_head;
    float *p_run = vbuf;
    while( p_tp ) {
        float *pfbuf = p_run;
        GLdouble *pdouble_buf = (GLdouble *)p_tp->p_vertex;
        
        for( int i=0 ; i < p_tp->nVert * 2 ; ++i){
            float x = (float)( *((GLdouble *)pdouble_buf) );
            pdouble_buf++;
            *p_run++ = x;
        }
        
        free(p_tp->p_vertex);
        p_tp->p_vertex = (double *)pfbuf;
        p_tp = p_tp->p_next; // pick up the next in chain
    }
    m_ppg_head->bsingle_alloc = true;
    m_ppg_head->single_buffer = (unsigned char *)vbuf;
    m_ppg_head->single_buffer_size = total_byte_size;
    m_ppg_head->data_type = DATA_TYPE_FLOAT;
    
    
    
    
    
    
    gluDeleteTess(GLUtessobj);

    free( m_pwork_buf );
    m_pwork_buf = NULL;

    free (geoPt);

    //      Free up any "Combine" vertices created
    for(unsigned int i = 0; i < m_pCombineVertexArray->GetCount() ; i++)
          free (m_pCombineVertexArray->Item(i));
    delete m_pCombineVertexArray;

    m_bOK = true;

    
    return 0;
}
Example #8
0
//      Build PolyTessGeo Object from OGR Polygon
PolyTessGeo::PolyTessGeo(OGRPolygon *poly, bool bSENC_SM, double ref_lat, double ref_lon,
                         double LOD_meters)
{
    m_printStats = false;
    
    ErrorCode = 0;
    m_ppg_head = NULL;
    m_pxgeom = NULL;
    m_tess_orient = TESS_HORZ;
    
    m_ref_lat = ref_lat;
    m_ref_lon = ref_lon;
    m_LOD_meters = LOD_meters;
    m_b_senc_sm = bSENC_SM;
    m_bmerc_transform = false;
    
    //    PolyGeo BBox as lat/lon
    OGREnvelope Envelope;
    poly->getEnvelope(&Envelope);
    xmin = Envelope.MinX;
    ymin = Envelope.MinY;
    xmax = Envelope.MaxX;
    ymax = Envelope.MaxY;

    m_feature_ref_lat = ymin + (ymax - ymin)/2;
    m_feature_ref_lon = xmin + (xmax - xmin)/2;
    
    toSM(m_feature_ref_lat, m_feature_ref_lon, ref_lat, ref_lon, &m_feature_easting, &m_feature_northing);

    //  Build the array of contour point counts
    //      Get total number of contours
    m_ncnt = poly->getNumInteriorRings() + 1;

      // build the contour point countarray
    m_cntr = (int *)malloc(m_ncnt * sizeof(int));

    m_cntr[0] = poly->getExteriorRing()->getNumPoints();

    for(int i = 1; i < m_ncnt ; i++){
          m_cntr[i] = poly->getInteriorRing( i-1 )->getNumPoints();
    }

    //  Build the point array index table
    
    OGRPoint p;
    m_vertexPtrArray = (double **)malloc(m_ncnt * sizeof(double *));
    
    m_vertexPtrArray[0] = (double *)malloc(m_cntr[0] * sizeof(double) * 2);
    double *pp = m_vertexPtrArray[0];
    for(int i = 0 ; i < m_cntr[0] ; i++){
        poly->getExteriorRing()->getPoint(i, &p);
        
        //  Calculate SM from feature reference point
        double easting, northing;
        toSM(p.getY(), p.getX(), m_feature_ref_lat, m_feature_ref_lon, &easting, &northing);
        *pp++ = easting;              // x
        *pp++ = northing;             // y
    }

    for(int i = 1; i < m_ncnt ; i++){
        m_vertexPtrArray[i] = (double *)malloc(m_cntr[i] * sizeof(double) * 2);
        double *pp = m_vertexPtrArray[i];
        for(int j = 0 ; j < m_cntr[i] ; j++){
            poly->getInteriorRing(i-1)->getPoint(j, &p);

            double easting, northing;
            toSM(p.getY(), p.getX(), m_feature_ref_lat, m_feature_ref_lon, &easting, &northing);
            *pp++ = easting;              // x
            *pp++ = northing;             // y
        }
    }
       

  
    mx_rate = 1.0;
    mx_offset = 0.0;
    my_rate = 1.0;
    my_offset = 0.0;

    m_bstripify = true;

    earthAxis = CM93_semimajor_axis_meters * mercator_k0;

    m_bcm93 = false;
    
    BuildTessGLU();
    
    // Free the working memory
    for(int i = 0; i < m_ncnt ; i++)
        free (m_vertexPtrArray[i]);
    
    free( m_vertexPtrArray );
    m_vertexPtrArray = nullptr;
    
}
Example #9
0
bool Routeman::UpdateProgress()
{
    bool bret_val = false;

    if( pActiveRoute ) {
//      Update bearing, range, and crosstrack error

//  Bearing is calculated as Mercator Sailing, i.e. a  cartographic "bearing"
        double north, east;
        toSM( pActivePoint->m_lat, pActivePoint->m_lon, gLat, gLon, &east, &north );
        double a = atan( north / east );
        if( fabs( pActivePoint->m_lon - gLon ) < 180. ) {
            if( pActivePoint->m_lon > gLon ) CurrentBrgToActivePoint = 90. - ( a * 180 / PI );
            else
                CurrentBrgToActivePoint = 270. - ( a * 180 / PI );
        } else {
            if( pActivePoint->m_lon > gLon ) CurrentBrgToActivePoint = 270. - ( a * 180 / PI );
            else
                CurrentBrgToActivePoint = 90. - ( a * 180 / PI );
        }

//      Calculate range using Great Circle Formula

        double d5 = DistGreatCircle( gLat, gLon, pActivePoint->m_lat, pActivePoint->m_lon );
        CurrentRngToActivePoint = d5;

//      Get the XTE vector, normal to current segment
        vector2D va, vb, vn;

        double brg1, dist1, brg2, dist2;
        DistanceBearingMercator( pActivePoint->m_lat, pActivePoint->m_lon,
                                 pActiveRouteSegmentBeginPoint->m_lat, pActiveRouteSegmentBeginPoint->m_lon, &brg1,
                                 &dist1 );
        vb.x = dist1 * sin( brg1 * PI / 180. );
        vb.y = dist1 * cos( brg1 * PI / 180. );

        DistanceBearingMercator( pActivePoint->m_lat, pActivePoint->m_lon, gLat, gLon, &brg2,
                                 &dist2 );
        va.x = dist2 * sin( brg2 * PI / 180. );
        va.y = dist2 * cos( brg2 * PI / 180. );

        double sdelta = vGetLengthOfNormal( &va, &vb, &vn );             // NM
        CurrentXTEToActivePoint = sdelta;

//    Calculate the distance to the arrival line, which is perpendicular to the current route segment
//    Taking advantage of the calculated normal from current position to route segment vn
        vector2D vToArriveNormal;
        vSubtractVectors( &va, &vn, &vToArriveNormal );

        CurrentRangeToActiveNormalCrossing = vVectorMagnitude( &vToArriveNormal );

//          Compute current segment course
//          Using simple Mercater projection
        double x1, y1, x2, y2;
        toSM( pActiveRouteSegmentBeginPoint->m_lat, pActiveRouteSegmentBeginPoint->m_lon,
              pActiveRouteSegmentBeginPoint->m_lat, pActiveRouteSegmentBeginPoint->m_lon, &x1,
              &y1 );

        toSM( pActivePoint->m_lat, pActivePoint->m_lon, pActiveRouteSegmentBeginPoint->m_lat,
              pActiveRouteSegmentBeginPoint->m_lon, &x2, &y2 );

        double e1 = atan2( ( x2 - x1 ), ( y2 - y1 ) );
        CurrentSegmentCourse = e1 * 180 / PI;
        if( CurrentSegmentCourse < 0 ) CurrentSegmentCourse += 360;

        //      Compute XTE direction
        double h = atan( vn.y / vn.x );
        if( vn.x > 0 ) CourseToRouteSegment = 90. - ( h * 180 / PI );
        else
            CourseToRouteSegment = 270. - ( h * 180 / PI );

        h = CurrentBrgToActivePoint - CourseToRouteSegment;
        if( h < 0 ) h = h + 360;

        if( h > 180 ) XTEDir = 1;
        else
            XTEDir = -1;

//      Determine Arrival

        bool bDidArrival = false;

        if( CurrentRangeToActiveNormalCrossing <= pActiveRoute->GetRouteArrivalRadius() ) {
            m_bArrival = true;
            UpdateAutopilot();

            bDidArrival = true;

            if( !ActivateNextPoint( pActiveRoute, false ) )            // at the end?
            {
                Route *pthis_route = pActiveRoute;
                DeactivateRoute( true );                  // this is an arrival
                if( pthis_route->m_bDeleteOnArrival ) {
                    pConfig->DeleteConfigRoute( pthis_route );
                    DeleteRoute( pthis_route );
                    if( pRoutePropDialog ) {
                        pRoutePropDialog->SetRouteAndUpdate( NULL );
                        pRoutePropDialog->UpdateProperties();
                    }
                    if( pRouteManagerDialog ) pRouteManagerDialog->UpdateRouteListCtrl();

                }
            }

        }

        if( !bDidArrival )                                        // Only once on arrival
            UpdateAutopilot();

        bret_val = true;                                        // a route is active
    }

    m_bDataValid = true;

    return bret_val;
}
Example #10
0
void WVSChart::RenderViewOnDC(wxMemoryDC& dc, ViewPort& VPoint)
{
        float *platray = NULL;
        float *plonray = NULL;
        int *psegray = NULL;
        int x,y;
        if(!m_ok)
                return;

//      Set Color
        wxPen *pthispen = wxThePenList->FindOrCreatePen(GetGlobalColor(_T("BLUE3")), 1, wxSOLID);
        dc.SetPen(*pthispen);

//      Compute the 1 degree cell boundaries

        int lat_min = (int)floor(VPoint.GetBBox().GetMinY());
        int lat_max = (int)ceil(VPoint.GetBBox().GetMaxY());
        int lon_min = (int)floor(VPoint.GetBBox().GetMinX());
        int lon_max = (int)ceil(VPoint.GetBBox().GetMaxX());

        x = lon_min;
        y = lat_min;

//        printf("%d %d\n", lon_min, lon_max);

        //  Make positive definite longitude for easier integer math
        lon_min += 720;
        lon_max += 720;

        double ref_lon = VPoint.clon;

//      Loop around the lat/lon spec to get and draw the vector segments
        for(y = lat_min ; y < lat_max ; y++)
        {
                for(x = lon_min ; x < lon_max ; x++)
                {
//      Get the arrays of lat/lon vector segments
//      Sanity Check
                      int xt = x;
                      int yt = y;
//      Check the cache first
                        int ix = xt % 360; //xt + 180;                               // bias to positive
                        int iy = yt + 90;

                        if(  (ix > 359) || (ix < 0) || (iy > 179) || (iy < 0) )
                                continue;


                        if(-1 == nseg[ix][iy])                          // no data yet
                        {
                                                                                                     // so fill cache
                                platray = NULL;
                                plonray = NULL;
                                psegray = NULL;
                                int nsegments = wvsrtv (*pwvs_file_name,
                                        y, ix, &platray, &plonray, &psegray);
                                plat_ray[ix][iy] = platray;
                                plon_ray[ix][iy] = plonray;
                                pseg_ray[ix][iy] = psegray;
                                nseg[ix][iy] = nsegments;
//                                printf("load at %d %d \n", ix, iy);

                        }
 //                       else
 //                             printf("     from cache at %d %d \n", ix, iy);

                        if(nseg[ix][iy])
                        {
                                float *plat_seg = plat_ray[ix][iy];
                                float *plon_seg = plon_ray[ix][iy];
                                int *pseg_cnt = pseg_ray[ix][iy];
                                for(int iseg = 0 ; iseg < nseg[ix][iy] ; iseg++)
                                {
                                        int seg_cnt = *pseg_cnt++;
                                        if(seg_cnt > cur_seg_cnt_max)
                                        {
                                                cur_seg_cnt_max = seg_cnt;
                                                ptp = (wxPoint *)realloc(ptp, seg_cnt * sizeof(wxPoint));
                                        }
                                        wxPoint *pr = ptp;
                                        wxPoint p;



                                        for(int ip = 0 ; ip < seg_cnt ; ip++)
                                        {
                                                float plat = *plat_seg++;
                                                float plon = *plon_seg++;

                                                if(fabs(plon - ref_lon) > 180.)
                                                {
                                                      if(plon > ref_lon)
                                                            plon -= 360.;
                                                      else
                                                            plon += 360.;
                                                }


                                                double easting, northing;
                                                toSM(plat, plon + 360., VPoint.clat, ref_lon + 360., &easting, &northing);
                                                double epix = easting  * VPoint.view_scale_ppm;
                                                double npix = northing * VPoint.view_scale_ppm;

                                                double dx = epix * cos(VPoint.skew) + npix * sin(VPoint.skew);
                                                double dy = npix * cos(VPoint.skew) - epix * sin(VPoint.skew);
                                                p.x = (int)round((VPoint.pix_width  / 2) + dx);
                                                p.y = (int)round((VPoint.pix_height / 2) - dy);

                                                *pr = p;
                                                pr++;
                                        }
                                        dc.DrawLines(seg_cnt, ptp);
                                }
                        }
                }       // for x
        }       //for y
        platray = NULL;
        plonray = NULL;
        psegray = NULL;
        wvsrtv (_T("clean"), y, x, &platray, &plonray, &psegray);
}