static inline int ComputeState(const LLBBox &box, const contour_pt &p) { int state = 0; if(p.x >= box.GetMinLon()) { if(p.x > box.GetMaxLon()) state = 2; else state = 1; } if(p.y >= box.GetMinLat()) { if(p.y > box.GetMaxLat()) state += 6; else state += 3; } return state; }
LLRegion::LLRegion( const LLBBox& llbbox ) { InitBox(llbbox.GetMinLat(), llbbox.GetMinLon(), llbbox.GetMaxLat(), llbbox.GetMaxLon()); }
// slightly ugly, but efficient intersection algorithm bool LLRegion::NoIntersection(const LLBBox& box) const { return false; // there are occasional false positives we must fix first #if 0 double minx = box.GetMinLon(), maxx = box.GetMaxLon(), miny = box.GetMinLat(), maxy = box.GetMaxLat(); if(Contains(miny, minx)) return false; // test if any segment crosses the box for(std::list<poly_contour>::const_iterator i = contours.begin(); i != contours.end(); i++) { contour_pt l = *i->rbegin(); int state = ComputeState(box, l), lstate = state; if(state == 4) return false; for(poly_contour::const_iterator j = i->begin(); j != i->end(); j++) { contour_pt p = *j; int quadrant = p.x > l.x ? 1 : 0; if(p.y > l.y) quadrant += 2; switch(state*4 + quadrant) { case 0: goto skip; case 1: if(p.x >= minx) state = p.x > maxx ? 2 : 1; goto skip; case 2: if(p.y >= miny) state = p.y > maxy ? 6 : 3; goto skip; case 4: if(p.x < minx) state = 0; goto skip; case 5: if(p.x > maxx) state = 2; goto skip; case 8: if(p.x <= maxx) state = p.x < minx ? 0 : 1; goto skip; case 9: goto skip; case 11: if(p.y >= miny) state = p.y > maxy ? 8 : 5; goto skip; case 12: if(p.y < miny) state = 0; goto skip; case 14: if(p.y > maxy) state = 6; goto skip; case 21: if(p.y < miny) state = 2; goto skip; case 23: if(p.y > maxy) state = 8; goto skip; case 24: if(p.y <= maxy) state = p.y < miny ? 0 : 3; goto skip; case 26: goto skip; case 27: if(p.x >= minx) state = p.x > maxx ? 8 : 7; goto skip; case 30: if(p.x < minx) state = 6; goto skip; case 31: if(p.x > maxx) state = 8; goto skip; case 33: if(p.y <= maxy) state = p.y < miny ? 2 : 5; goto skip; case 34: if(p.x <= maxx) state = p.x < minx ? 6 : 7; goto skip; case 35: goto skip; } state = ComputeState(box, *j); if(state == 4) return false; switch(lstate) { #define TEST_CASE(NO_INT, CASEA, CASEB, CASEAB, AX, AY, BX, BY) \ switch(state) { NO_INT break; \ CASEAB if(TestPoint(l, p, BX##x, BY##y)) return false; \ CASEA if(TestPoint(p, l, AX##x, AY##y)) return false; break; \ CASEB if(TestPoint(l, p, BX##x, BY##y)) return false; break; \ default: printf("invalid state inner %d %d\n", lstate, state); } break; case 0: TEST_CASE(case 0: case 1: case 2: case 3: case 6:, case 5:, case 7:, case 8:, max, min, min, max) case 1: TEST_CASE(case 0: case 1: case 2:, case 5: case 8:, case 3: case 6:, case 7:, max, min, min, min) case 2: TEST_CASE(case 0: case 1: case 2: case 5: case 8:, case 7:, case 3:, case 6:, max, max, min, min) case 3: TEST_CASE(case 0: case 3: case 6:, case 1: case 2:, case 7: case 8:, case 5:, min, min, min, max) // case 4: return false; // should never hit case 5: TEST_CASE(case 2: case 5: case 8:, case 6: case 7:, case 0: case 1:, case 3:, max, max, max, min) case 6: TEST_CASE(case 0: case 3: case 6: case 7: case 8:, case 1:, case 5:, case 2:, min, min, max, max) case 7: TEST_CASE(case 6: case 7: case 8:, case 0: case 3:, case 2: case 5:, case 1:, min, max, max, max) case 8: TEST_CASE(case 2: case 5: case 6: case 7: case 8:, case 3:, case 1:, case 0:, min, max, max, min) default: printf("invalid state\n"); } skip: lstate = state; l = p; } } return true; #endif }
void Route::DrawGLLines( ViewPort &vp, ocpnDC *dc ) { #ifdef ocpnUSE_GL float pix_full_circle = WGS84_semimajor_axis_meters * mercator_k0 * 2 * PI * vp.view_scale_ppm; bool r1valid = false; wxPoint2DDouble r1; wxPoint2DDouble lastpoint; wxRoutePointListNode *node = pRoutePointList->GetFirst(); RoutePoint *prp2 = node->GetData(); cc1->GetDoubleCanvasPointPix( prp2->m_lat, prp2->m_lon, &lastpoint); if(GetnPoints() == 1 && dc) { // single point.. make sure it shows up for highlighting cc1->GetDoubleCanvasPointPix( prp2->m_lat, prp2->m_lon, &r1); dc->DrawLine(r1.m_x, r1.m_y, r1.m_x+2, r1.m_y+2); return; } // Handle offscreen points LLBBox bbox = vp.GetBBox(); // dc is passed for thicker highlighted lines (performance not very important) if( !dc ) glBegin(GL_LINES); for(node = node->GetNext(); node; node = node->GetNext()) { RoutePoint *prp1 = prp2; prp2 = node->GetData(); // Provisional, to properly set status of last point in route prp2->m_pos_on_screen = false; { wxPoint2DDouble r2; cc1->GetDoubleCanvasPointPix( prp2->m_lat, prp2->m_lon, &r2); if(wxIsNaN(r2.m_x)) { r1valid = false; continue; } lastpoint = r2; // For active track segment to ownship // don't need to perform calculations or render segment // if both points are past any edge of the vp // TODO: use these optimizations for dc mode bool lat1l = prp1->m_lat < bbox.GetMinLat(), lat2l = prp2->m_lat < bbox.GetMinLat(); bool lat1r = prp1->m_lat > bbox.GetMaxLat(), lat2r = prp2->m_lat > bbox.GetMaxLat(); if( (lat1l && lat2l) || (lat1r && lat2r) ) { r1valid = false; prp1->m_pos_on_screen = false; continue; } bool lon1l, lon1r, lon2l, lon2r; TestLongitude(prp1->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon1l, lon1r); TestLongitude(prp2->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon2l, lon2r); if( (lon1l && lon2l) || (lon1r && lon2r) ) { r1valid = false; prp1->m_pos_on_screen = false; continue; } if(!r1valid) { cc1->GetDoubleCanvasPointPix( prp1->m_lat, prp1->m_lon, &r1); if(wxIsNaN(r1.m_x)) continue; } // we must decide which way to go in longitude // for projections which wrap, in this case, we will render two lines // (one may often be off screen which would be nice to fix but complicate things here // anyway, in some cases both points are on screen, but the route wraps to either side // so two lines are needed to draw this properly double adder = 0; if( (vp.m_projection_type == PROJECTION_MERCATOR || vp.m_projection_type == PROJECTION_EQUIRECTANGULAR) ) { float olon = vp.clon > 0 ? vp.clon - 180 : vp.clon + 180; if(prp1->m_lon < prp2->m_lon) { if(prp2->m_lon - prp1->m_lon < 180) { if(olon > prp1->m_lon && olon < prp2->m_lon) adder = pix_full_circle; } else if(olon < prp1->m_lon || olon > prp2->m_lon) adder = -pix_full_circle; } else if(prp1->m_lon - prp2->m_lon < 180) { if(olon < prp1->m_lon && olon > prp2->m_lon) adder = -pix_full_circle; } else if(olon > prp1->m_lon || olon < prp2->m_lon) adder = pix_full_circle; } if( dc ) if(adder) { float adderc = cos(vp.rotation)*adder, adders = sin(vp.rotation)*adder; dc->DrawLine(r1.m_x, r1.m_y, r2.m_x + adderc, r2.m_y + adders); dc->DrawLine(r1.m_x - adderc, r1.m_y - adders, r2.m_x, r2.m_y); } else dc->DrawLine(r1.m_x, r1.m_y, r2.m_x, r2.m_y); else { glVertex2f(r1.m_x, r1.m_y); if(adder) { float adderc = cos(vp.rotation)*adder, adders = sin(vp.rotation)*adder; glVertex2f(r2.m_x+adderc, r2.m_y+adders); glVertex2f(r1.m_x-adderc, r1.m_y-adders); } glVertex2f(r2.m_x, r2.m_y); // cache screen position for arrows and points if(!r1valid) { prp1->m_pos_on_screen = !lat1l && !lat1r && !lon1l && !lon1r; prp1->m_screen_pos = r1; } prp2->m_pos_on_screen = !lat2l && !lat2r && !lon2l && !lon2r; prp2->m_screen_pos = r2; } r1 = r2; r1valid = true; } } if( !dc ) glEnd(); #endif }