/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2019, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2019 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "DbSystemServices.h" #include "DbHostAppServices.h" #include "RxRasterServices.h" #include "FlatMemStream.h" #include "DbGeoData.h" #include "OdDbGeoCoordinateSystem.h" #include "DbGeoMapPEImpl.h" #include "DbRasterVariables.h" #include "DbViewportTable.h" #include "DbViewportTableRecord.h" #include "DbViewport.h" #include "DbGeoMapFieldsPE.h" //#include #include #include #include #define STL_USING_ALL #include "OdaSTL.h" #ifndef WIN32 #include #endif #if defined(_WIN32) || defined(_WIN64) #else #include #endif void correctGeoPt(OdGePoint3d & res) { //X corrections if (fabs(res.x) > 180.) { double dX = res.x; if (dX <= 0.) { if (dX < -180.) { dX += 360.; } } else if (dX > 180.) { dX -= 360.; } res.x = dX; } //Y corrections if (fabs(res.y) > 90.) { double dY = res.y; if (dY <= 0.) { if (dY >= -270.) { if (dY < -90.) { dY = -180. - dY; } } else { dY += 360.; } } else if (dY >= 90.) { if (dY >= 270.) { dY -= 360.; } else { dY = 180. - dY; } } res.y = dY; } } void CreateRotateBmp3(float ugol, int g_Width, int g_Height, const std::vector& datainv, int& rw, int& rh, std::vector& data3out); //void IO_TRACE(const char* lpszFormat, ...) //{ // // va_list args; // va_start(args, lpszFormat); // // int nBuf; // static char szBuffer[512]; // nBuf = vsnprintf(szBuffer, sizeof(szBuffer), lpszFormat, args); // OutputDebugStringA(szBuffer); // va_end(args); //} static const OdUInt8 arCameraImage[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x4, 0x3, 0x0, 0x0, 0x0, 0xae, 0x5c, 0xb5, 0x55, 0x0, 0x0, 0x0, 0x18, 0x50, 0x4c, 0x54, 0x45, 0xf5, 0xf2, 0xee, 0xf2, 0xf0, 0xeb, 0xf0, 0xed, 0xe9, 0xea, 0xe7, 0xe3, 0xe4, 0xe1, 0xdd, 0xe0, 0xdd, 0xd9, 0xdd, 0xda, 0xd6, 0xd0, 0xcd, 0xca, 0x1d, 0x6f, 0xdc, 0x99, 0x0, 0x0, 0x3, 0xac, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xda, 0x31, 0x53, 0xe3, 0x48, 0x10, 0x5, 0xe0, 0x96, 0x84, 0x73, 0x3, 0xde, 0x5c, 0x8b, 0x4c, 0x2e, 0x7b, 0x24, 0xe2, 0x65, 0xad, 0xd9, 0x98, 0x43, 0x7a, 0x22, 0xbe, 0xaa, 0xb5, 0x88, 0xb7, 0xae, 0xf0, 0xfc, 0xfd, 0xb, 0x66, 0x84, 0x65, 0x90, 0x33, 0xa6, 0x5d, 0x77, 0xf5, 0xbe, 0x8, 0x96, 0x60, 0x9e, 0xbb, 0x5b, 0x23, 0x69, 0xbc, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xff, 0x61, 0x49, 0x51, 0x35, 0x40, 0xb3, 0x33, 0xd7, 0x97, 0x59, 0xbf, 0xa8, 0x10, 0x34, 0xdb, 0xe5, 0x5, 0x3e, 0xbe, 0xc1, 0xc4, 0x2e, 0x57, 0x5f, 0x7f, 0x8d, 0x13, 0xad, 0x76, 0x2, 0x5f, 0xfe, 0xc6, 0x6c, 0xb, 0xe3, 0x7f, 0xdc, 0xe9, 0x76, 0xa1, 0x0, 0x80, 0x2e, 0xb4, 0xde, 0xf, 0xc3, 0x4e, 0x73, 0xfd, 0xcc, 0x9e, 0xf4, 0xdd, 0xcf, 0xc3, 0x56, 0x71, 0x0, 0x6a, 0x0, 0x66, 0x5a, 0xf3, 0xc2, 0x2, 0x9d, 0xde, 0x18, 0xdc, 0x7e, 0xee, 0x79, 0x61, 0x15, 0x9b, 0x90, 0xd8, 0x99, 0x99, 0x2b, 0x0, 0x94, 0x4a, 0x1, 0x56, 0xb3, 0x57, 0x5d, 0x5, 0xb4, 0x7a, 0x5, 0xd8, 0x7c, 0xfe, 0xe7, 0xd4, 0x6a, 0x95, 0xe0, 0xf6, 0x4c, 0xb7, 0xbf, 0x69, 0x95, 0xa0, 0x3e, 0x33, 0xef, 0x50, 0xba, 0x10, 0x32, 0x3b, 0xff, 0x41, 0x17, 0x0, 0xf0, 0xa8, 0x10, 0x60, 0x7d, 0xa6, 0xd5, 0xfe, 0x96, 0xa0, 0xd2, 0x81, 0x76, 0x79, 0xa6, 0x0, 0x15, 0x10, 0xbf, 0x7, 0x19, 0xf0, 0xf3, 0x4c, 0x1, 0x9e, 0x32, 0x8d, 0x1e, 0xac, 0xe6, 0x3b, 0xb0, 0x0, 0x20, 0x89, 0x55, 0xe8, 0x41, 0x8d, 0x6e, 0x79, 0xa6, 0x0, 0x67, 0xff, 0xf8, 0x95, 0xc6, 0xf, 0x99, 0xdc, 0x7d, 0x2a, 0x40, 0x71, 0xb6, 0x3c, 0x5f, 0x3c, 0x2, 0xa5, 0xbf, 0x16, 0x36, 0x85, 0x31, 0x66, 0x6b, 0xbc, 0xe1, 0x70, 0xf8, 0xa7, 0xda, 0xbe, 0xff, 0x55, 0x21, 0x40, 0x8d, 0xbf, 0xee, 0x1, 0x54, 0xc3, 0x30, 0xc, 0xc3, 0xf0, 0xea, 0x86, 0x83, 0x69, 0xb0, 0x11, 0x8b, 0xe7, 0xe8, 0xbb, 0x40, 0xb7, 0x4c, 0x8c, 0x31, 0x55, 0x65, 0x4c, 0x55, 0x99, 0xa, 0xd, 0x76, 0xbb, 0x9d, 0x7b, 0xdb, 0x3f, 0x89, 0xb1, 0x9d, 0xd4, 0xd1, 0xa7, 0xb0, 0x46, 0x2b, 0x69, 0x3f, 0xc, 0x0, 0xfa, 0xae, 0x1, 0x5a, 0x79, 0x28, 0x65, 0xe1, 0xe, 0x10, 0xa9, 0x4c, 0x2b, 0xab, 0xe8, 0x53, 0x58, 0xe3, 0x59, 0x52, 0xff, 0x20, 0xdc, 0x97, 0x2, 0xb4, 0x72, 0x5f, 0xa, 0xdc, 0xe1, 0x49, 0xe4, 0xa1, 0xdd, 0x48, 0x16, 0x7b, 0x2b, 0x4a, 0x2c, 0x7e, 0xbc, 0x7, 0xd8, 0xdc, 0x0, 0xdd, 0xf5, 0xaf, 0x72, 0x1, 0x77, 0x10, 0x91, 0x7, 0xe4, 0x92, 0xc6, 0x9e, 0xc2, 0x14, 0x28, 0xc7, 0x0, 0xc1, 0xbe, 0x75, 0xaf, 0xee, 0x4f, 0x8, 0x90, 0xd8, 0xc8, 0xcf, 0xa6, 0x19, 0xfc, 0xc7, 0x9c, 0xac, 0x8f, 0x17, 0xe7, 0x5c, 0x5b, 0x55, 0xc6, 0x22, 0x17, 0xa9, 0x23, 0x3f, 0x19, 0x66, 0xe8, 0x96, 0x27, 0x1, 0xba, 0xed, 0xf5, 0xf0, 0xea, 0xde, 0x30, 0xf4, 0x3, 0x94, 0x2, 0xc8, 0x34, 0xc0, 0xbe, 0x94, 0x5, 0x7a, 0x17, 0x7e, 0xcb, 0x45, 0xaa, 0xc8, 0xd7, 0xe1, 0x15, 0xda, 0x69, 0x80, 0xfe, 0xa7, 0x8, 0x80, 0xf6, 0x18, 0x60, 0x8d, 0x4e, 0x33, 0x0, 0x96, 0xfe, 0x36, 0xf8, 0xf0, 0x1e, 0x60, 0x15, 0x39, 0xc0, 0xe2, 0x34, 0x40, 0x1b, 0x6e, 0x83, 0x57, 0xef, 0x1, 0xae, 0xa2, 0x7, 0x78, 0x9e, 0x6, 0xf8, 0xe1, 0xb, 0x20, 0xd9, 0x24, 0x0, 0x14, 0x3, 0xf4, 0x65, 0x78, 0xe, 0x48, 0xac, 0x5e, 0x80, 0x93, 0x16, 0xe4, 0xbe, 0x0, 0x22, 0x56, 0xab, 0x5, 0x1f, 0x86, 0x70, 0xe9, 0xb, 0x20, 0x61, 0xa, 0x15, 0x86, 0xf0, 0x43, 0x80, 0x6f, 0xa1, 0x0, 0xc7, 0x0, 0xca, 0x97, 0xe1, 0x3e, 0x14, 0xe0, 0x18, 0xe0, 0x3e, 0xf2, 0x46, 0x74, 0xba, 0x13, 0xbe, 0xec, 0x43, 0x1, 0x92, 0x5f, 0x63, 0x80, 0x3a, 0x7a, 0x80, 0xe9, 0xcd, 0xc8, 0xbd, 0x85, 0x2, 0xa4, 0x38, 0x6, 0x88, 0x7d, 0x2f, 0x98, 0xdc, 0x8e, 0x5f, 0xdc, 0x21, 0x5c, 0x73, 0xd9, 0x3e, 0x4, 0x48, 0xec, 0xfc, 0x6b, 0xcb, 0x97, 0x49, 0xec, 0x24, 0x80, 0x73, 0xce, 0x17, 0x40, 0xea, 0xb1, 0x2, 0xa9, 0x9d, 0x3b, 0x3a, 0xf8, 0xda, 0x0, 0x8f, 0x63, 0x80, 0x17, 0xe7, 0x5c, 0x39, 0xed, 0x0, 0x72, 0x85, 0xe7, 0xf2, 0x1a, 0xbb, 0x71, 0x3d, 0xe7, 0xdc, 0xdb, 0xef, 0xe5, 0xa4, 0x0, 0xc8, 0xe5, 0x2a, 0xfa, 0x11, 0xc1, 0x3d, 0xda, 0x10, 0xe0, 0xc5, 0x39, 0x87, 0xbe, 0xfd, 0x3e, 0x39, 0xb5, 0xcd, 0xa3, 0x5f, 0x85, 0x22, 0x2b, 0x74, 0x79, 0xda, 0x8f, 0x5, 0x0, 0xfa, 0x6e, 0x67, 0x8f, 0x3b, 0xb3, 0xc2, 0x7b, 0x41, 0x6, 0x94, 0x89, 0x1d, 0xb, 0x0, 0xc0, 0xbf, 0x23, 0x84, 0x0, 0xa9, 0x8d, 0xfe, 0x7e, 0x9e, 0x86, 0xeb, 0x2c, 0xe9, 0x87, 0xe1, 0xef, 0xeb, 0xeb, 0x9b, 0x3b, 0xaf, 0xb8, 0xdb, 0x9a, 0xc2, 0x2c, 0x15, 0xde, 0xd, 0xc7, 0x22, 0x8f, 0xb7, 0xc1, 0x53, 0x6b, 0x85, 0x63, 0xaa, 0xb0, 0xc6, 0x78, 0x1b, 0x9c, 0x4d, 0x17, 0x7f, 0x2f, 0x3c, 0x53, 0x80, 0x14, 0x91, 0xf7, 0xc1, 0xb0, 0x15, 0xb5, 0xe7, 0xa, 0xb0, 0x52, 0x39, 0x2b, 0xad, 0xd1, 0xe5, 0xf3, 0x5, 0xd0, 0x38, 0xa1, 0xf1, 0x3d, 0x78, 0x9c, 0x2f, 0x40, 0xa6, 0xd1, 0x1, 0x7f, 0x28, 0x3d, 0x5f, 0x80, 0xb5, 0xd2, 0x69, 0xf5, 0x1a, 0xf3, 0x5, 0x48, 0xad, 0xd2, 0x61, 0x75, 0x66, 0xe7, 0xb, 0x50, 0xe9, 0x1c, 0x15, 0x8b, 0x48, 0x3d, 0x7b, 0x26, 0x7c, 0xb, 0x95, 0x11, 0xc, 0xc3, 0xf6, 0xf9, 0xb1, 0x23, 0xb5, 0x6a, 0x5, 0x10, 0xa9, 0x81, 0xee, 0x43, 0x82, 0xb4, 0xd6, 0x2b, 0x80, 0x9f, 0x82, 0xd3, 0x4d, 0x3f, 0xad, 0x80, 0xc8, 0xf, 0x63, 0x27, 0x56, 0x0, 0x9a, 0xcd, 0x87, 0xf5, 0x35, 0xbf, 0x3a, 0x4d, 0xea, 0xc9, 0x37, 0xb7, 0x92, 0x14, 0x16, 0xaa, 0xdf, 0x5b, 0xca, 0xb8, 0x1b, 0xed, 0xcc, 0xf7, 0xa5, 0xdc, 0x14, 0x95, 0xc5, 0xe7, 0xa1, 0x88, 0xed, 0xb6, 0xf1, 0x5f, 0x9f, 0x37, 0x4d, 0x13, 0xe, 0xab, 0x44, 0xd9, 0x6d, 0x8d, 0x93, 0xc3, 0x32, 0x51, 0x97, 0x56, 0xc7, 0xf5, 0x9b, 0x8d, 0x5c, 0x82, 0x6f, 0x3e, 0xd0, 0x98, 0xfc, 0x22, 0xeb, 0x4b, 0x52, 0x98, 0xc6, 0x76, 0x8d, 0xb9, 0xc4, 0x7f, 0x61, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xff, 0x91, 0x7f, 0x1, 0x58, 0xd3, 0x74, 0x39, 0x27, 0xe5, 0x82, 0xe3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; //this class was taken from DbGeoMap.cpp class OdGiRasterImageRGBA32 : public OdGiRasterImageBGRA32 { public: OdGiRasterImage::PixelFormatInfo pixelFormat() const { OdGiRasterImage::PixelFormatInfo pf; pf.setRGBA(); return pf; } static OdGiRasterImagePtr createObject(OdGiImageBGRA32 *pImage, OdGiRasterImage::TransparencyMode transparencyMode = OdGiRasterImage::kTransparency8Bit) { ODA_ASSERT(pImage); OdSmartPtr pIw = OdRxObjectImpl::createObject(); pIw->m_pBGRAImage = pImage; pIw->m_transparencyMode = transparencyMode; return pIw; } }; ODRX_CONS_DEFINE_MEMBERS(OdDbGeoMapPEImpl, OdDbGeoMapPE, RXIMPL_CONSTR); const double EarthRadius = 6378137; const double MinLatitude = -85.05112878; const double MaxLatitude = 85.05112878; const double MinLongitude = -180; const double MaxLongitude = 180; double Clip(double n, double minValue, double maxValue); unsigned int MapSize(int levelOfDetail); double GroundResolution(double latitude, int levelOfDetail); double MapScale(double latitude, int levelOfDetail, int screenDpi); void LatLongToPixelXY(double latitude, double longitude, int levelOfDetail, OdInt32 & pixelX, OdInt32 & pixelY); void PixelXYToLatLong(OdInt32 pixelX, OdInt32 pixelY, int levelOfDetail, double & latitude, double & longitude); void PixelXYToTileXY(OdInt32 pixelX, OdInt32 pixelY, OdInt32 & tileX, OdInt32 & tileY); void TileXYToPixelXY(OdInt32 tileX, OdInt32 tileY, OdInt32 & pixelX, OdInt32 & pixelY); OdAnsiString TileXYToQuadKey(OdInt32 tileX, OdInt32 tileY, int levelOfDetail); void QuadKeyToTileXY(const OdString & quadKey, OdInt32 & tileX, OdInt32 & tileY, int & levelOfDetail); void LatLongToTileXY(double latitude, double longitude, int levelOfDetail, OdInt32 & iTileX, OdInt32 & iTileY); void GoogleBingToWGS84Mercator(double x, double y, double & lat, double & lon); void WGS84ToGoogleBing(double lat, double lon, double & x, double & y); //bing maps stuff end void fillPixelData(OdBinaryData & pixelData, OdInt32 dataWidth, OdInt32 dataHeight, OdGiRasterImagePtr pRaster, OdInt32 posX, OdInt32 posY, bool transparency = false); class CurlAndCash { CURL *curl; CURLcode res; typedef std::deque < std::string > Deque; Deque m_deque; typedef std::map > Map; Map m_map; std::vector callbackbuffer; static size_t Callback(void *buffer, size_t size, size_t nmemb, void *param) { std::vector * pbuffer = (std::vector *)param; pbuffer->resize(pbuffer->size() + size * nmemb); memcpy(&pbuffer->operator[](0) + pbuffer->size() - size * nmemb, buffer, size*nmemb); return size * nmemb; } std::vector curlget(const std::string& addr) { curl_easy_setopt(curl, CURLOPT_URL, addr.c_str()); //IO_TRACE("GET curl_easy_setopt %s\n", addr.c_str()); callbackbuffer.resize(0); res = curl_easy_perform(curl); return callbackbuffer; } public: ~CurlAndCash() { curl_easy_cleanup(curl); //curl_global_cleanup(); } CurlAndCash() { //curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (!curl) { return; } curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &callbackbuffer); } std::vector curlget(const char* addr) { std::string adr(addr); Map::iterator f = m_map.find(adr); if (m_map.end() == f) { std::vector r = curlget(adr); m_map.insert(Map::value_type(adr, r)); m_deque.push_back(adr); if (m_deque.size() > 200) { std::string erasestr = m_deque.front(); m_deque.erase(m_deque.begin()); Map::iterator f1 = m_map.find(erasestr); if (m_map.end() == f1) { ODA_ASSERT_ONCE(!"BAD CASH !!"); } else m_map.erase(f1); } return r; } else return f->second; } }; CurlAndCash* g_CurlAndCash = 0; class CurlMultiAndCash; CurlMultiAndCash* g_CurlMultiAndCash = 0; class CurlMultiAndCash { CURLM *cm; CURLMsg *msg; enum { MAX = 20 };/// mfrcbvev CURL *curl; CURLcode res; typedef std::deque < std::string > Deque; Deque m_deque; typedef std::map > Map; Map m_map; std::vector callbackbuffer; std::vector > m_res; std::vector m_addr; static size_t Callback(void *buffer, size_t size, size_t nmemb, void *param) { std::vector * pbuffer = (std::vector *)param; pbuffer->resize(pbuffer->size() + size * nmemb); memcpy(&pbuffer->operator[](0) + pbuffer->size() - size * nmemb, buffer, size*nmemb); return size * nmemb; } static size_t Callback1(void *buffer, size_t size, size_t nmemb, void *param) { std::vector * pbuffer = &g_CurlMultiAndCash->m_res[*((int*)(¶m))]; pbuffer->resize(pbuffer->size() + size * nmemb); memcpy(&pbuffer->operator[](0) + pbuffer->size() - size * nmemb, buffer, size*nmemb); //IO_TRACE("add N=%d size= %d\n", (int)param, pbuffer->size()); return size * nmemb; } void init(int i) { CURL *eh = curl_easy_init(); curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, Callback1); curl_easy_setopt(eh, CURLOPT_HEADER, 0L); curl_easy_setopt(eh, CURLOPT_URL, m_addr[i].c_str()); //IO_TRACE("N=%d url %s\n", i, m_addr[i].c_str()); curl_easy_setopt(eh, CURLOPT_PRIVATE, m_addr[i].c_str()); curl_easy_setopt(eh, CURLOPT_VERBOSE, 0L); curl_easy_setopt(eh, CURLOPT_WRITEDATA, i); curl_multi_add_handle(cm, eh); } std::vector get1(const std::string& addr) { curl_easy_setopt(curl, CURLOPT_URL, addr.c_str()); callbackbuffer.resize(0); res = curl_easy_perform(curl); return callbackbuffer; } std::vector >& curlmultiget1(const std::vector& addr) { //DWORD start = GetTickCount(); std::vector > r; for (unsigned int i = 0; i != addr.size(); i++) { curl_easy_setopt(curl, CURLOPT_URL, addr[i].c_str()); //IO_TRACE("N=%d url %s\n",i, addr[i].c_str()); callbackbuffer.resize(0); res = curl_easy_perform(curl); m_res.push_back(callbackbuffer); } //DWORD d = GetTickCount() - start; //IO_TRACE("TIME=%d %f\n", d,(float)d/(float) addr.size()); return m_res; } std::vector >& curlmultiget(const std::vector& addr) { //DWORD start = GetTickCount(); m_addr = addr; m_res.resize(m_addr.size()); for (int i = 0; i != m_res.size(); i++) { m_res[i].clear(); } ///the code is copied from the example. Almost no changes were needed. Original style saved /// https://curl.haxx.se/libcurl/c/10-at-a-time.html unsigned int C = 0; int M, Q, U = -1; fd_set R, W, E; struct timeval T; long L; for (C = 0; C select(M + 1, &R, &W, &E, &T)) { //IO_TRACE( "E: select(%i,,,,%li): %i: %s\n", M + 1, L, errno, strerror(errno)); return m_res; } } } while ((msg = curl_multi_info_read(cm, &Q))) { if (msg->msg == CURLMSG_DONE) { char *url; CURL *e = msg->easy_handle; curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url); if(CURLE_OK!= msg->data.result) //IO_TRACE( "R: %d - %s <%s>\n",msg->data.result, curl_easy_strerror(msg->data.result), url); curl_multi_remove_handle(cm, e); curl_easy_cleanup(e); } else { //IO_TRACE( "E: CURLMsg (%d)\n", msg->msg); } if (C < addr.size()) { init(C++); U++; /* just to prevent it from remaining at 0 if there are more URLs to get */ } } } //DWORD d = GetTickCount() - start; //IO_TRACE("TIME=%d %f\n", d, (float)d / (float)addr.size()); return m_res; } public: template std::vector curlget1nocash(const STR& addr) { curl_easy_setopt(curl, CURLOPT_URL, addr.c_str()); callbackbuffer.resize(0); res = curl_easy_perform(curl); return callbackbuffer; } ~CurlMultiAndCash() { curl_multi_cleanup(cm); curl_global_cleanup(); } CurlMultiAndCash() { curl_global_init(CURL_GLOBAL_DEFAULT); cm = curl_multi_init(); if (!cm) { return; } //we can optionally limit the total amount of connections this multi handle uses curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)MAX); curl = curl_easy_init(); if (!curl) { return; } curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &callbackbuffer); } std::vector > curlget(std::vector& addr) { std::vector > res; res.resize(addr.size()); std::vector absence; std::vector absencenum; for (unsigned int i = 0; i != addr.size(); i++) { std::string adr(addr[i]); Map::iterator f = m_map.find(adr); if (m_map.end() == f) absence.push_back(adr), absencenum.push_back(i); else res[i] = f->second; } std::vector >& r1 = curlmultiget(absence); for (unsigned int i = 0; i != r1.size(); i++) { std::vector r = r1[i]; res[absencenum[i]] = r; if (!r.empty()) { const std::string& adr = absence[i]; m_map.insert(Map::value_type(adr, r)); m_deque.push_back(adr); if (m_deque.size() > 200)/// 200 bimap only may be increase/decrease { std::string erasestr = m_deque.front(); m_deque.erase(m_deque.begin()); Map::iterator f1 = m_map.find(erasestr); if (m_map.end() == f1) { ODA_ASSERT_ONCE(!"BAD CASH !!"); } else m_map.erase(f1); } } } return res; } }; class ProviderHelper { std::vector logo; OdStringArray copyrightStrings; char cMapTypeIdMetaDataOld; public: OdStringArray GetStrings(int iCorrectedLOD, char cMapTypeIdMetaData, const OdGePoint3d& ptImageUpperLeftLLA, const OdGePoint3d& ptImageBottomRightLLA) { if (cMapTypeIdMetaDataOld != cMapTypeIdMetaData) { TestProvider(iCorrectedLOD, cMapTypeIdMetaData, ptImageUpperLeftLLA, ptImageBottomRightLLA); cMapTypeIdMetaDataOld = cMapTypeIdMetaData; } return copyrightStrings; } const std::vector& GetStreamLogo() { return logo; } OdResult TestProvider(int iCorrectedLOD, char cMapTypeIdMetaData, const OdGePoint3d& ptImageUpperLeftLLA, const OdGePoint3d& ptImageBottomRightLLA) { OdResult res = eOk; OdGeExtents2d imageGeoExtents; imageGeoExtents.addPoint(OdGePoint2d(ptImageUpperLeftLLA.x, ptImageUpperLeftLLA.y)); imageGeoExtents.addPoint(OdGePoint2d(ptImageBottomRightLLA.x, ptImageBottomRightLLA.y)); copyrightStrings.clear(); OdAnsiString sImageryProvidersUrl; OdString sBingMapsKey; odrxSystemServices()->getEnvVar(L"CS_MAP_KEY", sBingMapsKey); sImageryProvidersUrl.format("http://dev.virtualearth.net/REST/v1/Imagery/Metadata/%c?incl=ImageryProviders&o=xml&key=%s", cMapTypeIdMetaData, sBingMapsKey.c_str()); std::vector Metadata = g_CurlMultiAndCash->curlget1nocash(sImageryProvidersUrl); if (Metadata.empty()) { return eInvalidInput; } Metadata.resize(Metadata.size() + 1); Metadata[Metadata.size() - 1] = 0; TiXmlDocument doc; doc.Parse((char *)&Metadata[0], 0, TIXML_ENCODING_UTF8); TiXmlHandle docHandle(&doc); TiXmlElement * imageryMetadata = docHandle. FirstChild("Response"). FirstChild("ResourceSets"). FirstChild("ResourceSet"). FirstChild("Resources"). FirstChild("ImageryMetadata"). ToElement(); if (imageryMetadata) { for (TiXmlElement* imageryProvider = imageryMetadata->FirstChildElement("ImageryProvider"); imageryProvider != NULL; imageryProvider = imageryProvider->NextSiblingElement("ImageryProvider")) { for (TiXmlElement* coverageArea = imageryProvider->FirstChildElement("CoverageArea"); coverageArea != NULL; coverageArea = coverageArea->NextSiblingElement("CoverageArea")) { int iZoomMin = atoi(coverageArea->FirstChildElement("ZoomMin")->GetText()); int iZoomMax = atoi(coverageArea->FirstChildElement("ZoomMax")->GetText()); if (iCorrectedLOD >= iZoomMin && iCorrectedLOD <= iZoomMax) { bool bAddProvider = false; for (TiXmlElement* boundingBox = coverageArea->FirstChildElement("BoundingBox"); boundingBox != NULL; boundingBox = boundingBox->NextSiblingElement("BoundingBox")) { OdGeExtents2d providerExtents; OdGePoint2d p1, p2; p1.y = odStrToD(boundingBox->FirstChildElement("SouthLatitude")->GetText()); p1.x = odStrToD(boundingBox->FirstChildElement("WestLongitude")->GetText()); p2.y = odStrToD(boundingBox->FirstChildElement("NorthLatitude")->GetText()); p2.x = odStrToD(boundingBox->FirstChildElement("EastLongitude")->GetText()); providerExtents.addPoint(p1); providerExtents.addPoint(p2); if (!providerExtents.isDisjoint(imageGeoExtents)) { bAddProvider = true; break; } } if (bAddProvider) { OdString sImageryProvider = imageryProvider->FirstChildElement("Attribution")->GetText(); copyrightStrings.append(sImageryProvider.c_str() + 1); break; } } } } } else res = eOk; OdAnsiString imageUrl("http://dev.virtualearth.net/Branding/logo_powered_by.png"); logo = g_CurlMultiAndCash->curlget1nocash(imageUrl); return res; } }; ProviderHelper* g_ProviderHelper = 0; OdDbGeoMapPEImpl::~OdDbGeoMapPEImpl() { if (0 != g_CurlMultiAndCash) delete g_CurlMultiAndCash; if (0 != g_ProviderHelper) delete g_ProviderHelper; } OdResult getMap(const OdDbGeoMap * pGeoMap, OdBinaryData & imgPixelData, OdStringArray & copyrightStrings, OdInt8 & LOD) { if (pGeoMap == NULL) { return eNullPtr; } OdRxRasterServicesPtr pRasterSvcs = odrxDynamicLinker()->loadModule(RX_RASTER_SERVICES_APPNAME); //get geomap atributes OdBinaryData bufPixelData; OdGePoint3d ptImageBoottomLeft; OdGeVector3d u, v; pGeoMap->getOrientation(ptImageBoottomLeft, u, v); OdGePoint3d ptImageUpperLeft = ptImageBoottomLeft + v; OdGePoint3d ptImageBottomRight = ptImageBoottomLeft + u; int iCorrectedLOD = odmin(odmax(pGeoMap->LOD() + pGeoMap->resolution(), 1), 21); OdGeoMapType eMapType = pGeoMap->mapType(); OdGeVector2d imgSize = pGeoMap->imageSize(); OdString sMapTypeId; sMapTypeId = (eMapType == kAerial) ? 'a' : (eMapType == kHybrid) ? 'h' : 'r'; OdDbObjectId objId; oddbGetGeoDataObjId(pGeoMap->database(), objId); OdDbGeoDataPtr pGeoData = objId.openObject(); if (pGeoData.isNull()) { return eNullPtr; } OdGePoint3d ptOldImageUpperLeft = ptImageUpperLeft; OdGePoint3d ptOldImageBottomRight = ptImageBottomRight; // check extents OdGeExtents2d ext; OdGeExtents2d geoExt; { //get cartersian extents of global map by geo-extents OdDbGeoCoordinateSystemPtr pCs; OdDbGeoCoordinateSystem::create(pGeoData->coordinateSystem(), pCs); OdGeExtents2d extGeo; pCs->getGeodeticExtents(extGeo); OdGePoint3d minGeo(extGeo.minPoint().x, extGeo.minPoint().y, 0.); OdGePoint3d maxGeo(extGeo.maxPoint().x, extGeo.maxPoint().y, 0.); // minGeo and maxGeo could be out of geo-extents, // so we must correct their values, and create new extents from it correctGeoPt(minGeo); correctGeoPt(maxGeo); geoExt.addPoint(minGeo.convert2d()); geoExt.addPoint(maxGeo.convert2d()); // get cartesian-extents for whole map (global), by converting geo2cartesian using geodata OdGePoint3d min; OdGePoint3d max; pGeoData->transformFromLonLatAlt(minGeo, min); pGeoData->transformFromLonLatAlt(maxGeo, max); ext.addPoint(min.convert2d()); ext.addPoint(max.convert2d()); // correction for XY: // check if geomap points is out of cartersian-extents // if so, update points to limit cartersian-extents values if (ptImageUpperLeft.x < ext.minPoint().x) { ptImageUpperLeft.x = ext.minPoint().x; } if (ptImageUpperLeft.y > ext.maxPoint().y) { ptImageUpperLeft.y = ext.maxPoint().y; } if (ptImageBottomRight.x > ext.maxPoint().x) { ptImageBottomRight.x = ext.maxPoint().x; } if (ptImageBottomRight.y < ext.minPoint().y) { ptImageBottomRight.y = ext.minPoint().y; } } // get geo-points for geomap OdGePoint3d ptImageUpperLeftLLA, ptImageBottomRightLLA; pGeoData->transformToLonLatAlt(ptImageUpperLeft, ptImageUpperLeftLLA); pGeoData->transformToLonLatAlt(ptImageBottomRight, ptImageBottomRightLLA); // correction for lat lon: // if old cartesian point is out of cartersian-extents, // then resulted geo-points also out of global geo-extents, so // update geomap geo-extents { if (ptOldImageUpperLeft.x < ext.minPoint().x) { ptImageUpperLeftLLA.x = geoExt.minPoint().x; } if (ptOldImageUpperLeft.y > ext.maxPoint().y) { ptImageUpperLeftLLA.y = geoExt.maxPoint().y; } if (ptOldImageBottomRight.x > ext.maxPoint().x) { ptImageBottomRightLLA.x = geoExt.maxPoint().x; } if (ptOldImageBottomRight.y < ext.minPoint().y) { ptImageBottomRightLLA.y = geoExt.minPoint().y; } } //get WORLD-MERCATOR image width, height OdInt32 iShiftXup, iShiftYup, iShiftXbot, iShiftYbot; LatLongToPixelXY(ptImageUpperLeftLLA.y, ptImageUpperLeftLLA.x, iCorrectedLOD, iShiftXup, iShiftYup); LatLongToPixelXY(ptImageBottomRightLLA.y, ptImageBottomRightLLA.x, iCorrectedLOD, iShiftXbot, iShiftYbot); OdInt32 imgWidth = iShiftXbot - iShiftXup + 1; OdInt32 imgHeight = iShiftYbot - iShiftYup + 1; if (imgWidth <= 0 || imgHeight <= 0) { return eInvalidExtents; } while (imgWidth > 4000 || imgHeight > 4000) { iCorrectedLOD -= 2; LatLongToPixelXY(ptImageUpperLeftLLA.y, ptImageUpperLeftLLA.x, iCorrectedLOD, iShiftXup, iShiftYup); LatLongToPixelXY(ptImageBottomRightLLA.y, ptImageBottomRightLLA.x, iCorrectedLOD, iShiftXbot, iShiftYbot); imgWidth = iShiftXbot - iShiftXup + 1; imgHeight = iShiftYbot - iShiftYup + 1; } LOD = iCorrectedLOD; bufPixelData.setLogicalLength(imgWidth * imgHeight * 4); bufPixelData.setAll(0); //calculate shift stuff OdInt32 iTileUpperLeftX, iTileUpperLeftY, iTileBottomRightX, iTileBottomRightY; LatLongToTileXY(ptImageUpperLeftLLA.y, ptImageUpperLeftLLA.x, iCorrectedLOD, iTileUpperLeftX, iTileUpperLeftY); LatLongToTileXY(ptImageBottomRightLLA.y, ptImageBottomRightLLA.x, iCorrectedLOD, iTileBottomRightX, iTileBottomRightY); OdInt32 iShiftX, iShiftY; iShiftX = iShiftXup - iTileUpperLeftX * 256; iShiftY = iShiftYup - iTileUpperLeftY * 256; if (0 == g_CurlMultiAndCash) g_CurlMultiAndCash = new CurlMultiAndCash(); char cMapTypeIdMetaData; cMapTypeIdMetaData = (eMapType == kAerial) ? '1' : (eMapType == kHybrid) ? '2' : '0'; // fill ImageryProviders strings if (0 == g_ProviderHelper) { g_ProviderHelper = new ProviderHelper(); OdResult ores = g_ProviderHelper->TestProvider(iCorrectedLOD, cMapTypeIdMetaData, ptImageUpperLeftLLA, ptImageBottomRightLLA); if (eOk != ores) return ores; } copyrightStrings = g_ProviderHelper->GetStrings(iCorrectedLOD, cMapTypeIdMetaData, ptImageUpperLeftLLA, ptImageBottomRightLLA); OdAnsiString sImageUrl; char cMapTypeId = (eMapType == kAerial) ? 'a' : (eMapType == kHybrid) ? 'h' : 'r'; std::vector addrs; for (OdInt32 i = iTileUpperLeftX; i <= iTileBottomRightX; ++i) { for (OdInt32 j = iTileUpperLeftY; j <= iTileBottomRightY; ++j) { OdAnsiString sQuadKey = TileXYToQuadKey(i, j, iCorrectedLOD); sImageUrl.format("http://tiles.virtualearth.net/tiles/%c%s?g=1&shading=hill", cMapTypeId, sQuadKey.c_str()); addrs.push_back(std::string(sImageUrl.c_str(), sImageUrl.getLength())); } } std::vector > r=g_CurlMultiAndCash->curlget(addrs); OdInt32 current = 0; for (OdInt32 i = iTileUpperLeftX; i <= iTileBottomRightX; ++i) { for (OdInt32 j = iTileUpperLeftY; j <= iTileBottomRightY; ++j) { const std::vector& r1 = r[current++]; OdStreamBufPtr pStream; if (r1.empty()) { pStream = OdFlatMemStream::createNew((void*)&arCameraImage[0], sizeof(arCameraImage)); } else pStream = OdFlatMemStream::createNew((void*)&r1[0], r1.size()); OdGiRasterImagePtr pRaster = pRasterSvcs->loadRasterImage(pStream); OdSmartPtr pDesc = OdGiRasterImageDesc::createObject(pRaster); pDesc->setPixelWidth(256); pDesc->setPixelHeight(256); pDesc->setColorDepth(32); pDesc->pixelFormat().setRGBA(); pDesc->setScanLinesAlignment(4); OdGiRasterImagePtr pConvertedRaster = pRaster->convert(true, 50., 50., 0.0, 0, false, true, false, pDesc); fillPixelData(bufPixelData, imgWidth, imgHeight, pConvertedRaster, (i - iTileUpperLeftX) * pConvertedRaster->pixelWidth() - iShiftX, (j - iTileUpperLeftY) * pConvertedRaster->pixelHeight() - iShiftY ); } } //paste image { OdGiImageBGRA32 pImg; pImg.setImage(imgWidth, imgHeight, (OdGiPixelBGRA32 *)bufPixelData.asArrayPtr()); OdGiRasterImagePtr pImage = OdGiRasterImageRGBA32::createObject(&pImg); OdSmartPtr pDesc = OdGiRasterImageDesc::createObject(pImage); double pixelWidth = (ptOldImageBottomRight.x - ptOldImageUpperLeft.x) / imgSize.x; double pixelHeight = (ptOldImageUpperLeft.y - ptOldImageBottomRight.y) / imgSize.y; OdInt32 newImgWidth = (ptImageBottomRight.x - ptImageUpperLeft.x) / pixelWidth; OdInt32 newImgHieght = (ptImageUpperLeft.y - ptImageBottomRight.y) / pixelHeight; pDesc->setPixelWidth(newImgWidth); pDesc->setPixelHeight(newImgHieght); pDesc->setColorDepth(32); pDesc->pixelFormat().setRGBA(); pDesc->setScanLinesAlignment(4); OdGiRasterImagePtr pRaster = pImage->convert(false, 50., 50., 0.0, 0, false, false, false, pDesc); const OdUInt8 * pData = pRaster->scanLines(); imgPixelData.setAll(0); fillPixelData(imgPixelData, imgSize.x, imgSize.y, pRaster, (ptImageUpperLeft.x - ptOldImageUpperLeft.x) / pixelWidth, (ptOldImageUpperLeft.y - ptImageUpperLeft.y) / pixelHeight ); } // loading bing logo "powered by" const std::vector& logo = g_ProviderHelper->GetStreamLogo(); OdFlatMemStreamPtr pStreamLogo = OdFlatMemStream::createNew((void*)&logo[0], logo.size()); OdGiRasterImagePtr pRasterLogo = pRasterSvcs->loadRasterImage(pStreamLogo); OdSmartPtr pDescLogo = OdGiRasterImageDesc::createObject(pRasterLogo); pDescLogo->setColorDepth(32); pDescLogo->pixelFormat().setRGBA(); pDescLogo->setScanLinesAlignment(4); OdGiRasterImagePtr pConvertedRaster = pRasterLogo->convert(false, 50., 50., 0.0, 0, false, true, false, pDescLogo, true); const OdUInt8 * pData = pConvertedRaster->scanLines(); OdInt32 rasterWidth = pConvertedRaster->pixelWidth(); OdInt32 rasterHeight = pConvertedRaster->pixelHeight(); //HDC hdc = GetDC(0); OdGePoint3dArray ptVertices; pGeoMap->getVertices(ptVertices); OdGeVector3d bott= (ptVertices[1] - ptVertices[0]).normalize(); double sinus = bott.y ; double cosus = bott.x ; double topixel = (ptVertices[1].x - ptVertices[3].x)*1.02 / imgSize.x; double dTextHeight1 = rasterWidth * topixel; OdGePoint3d ptTextPosition = ptVertices[1] - 0.9 *bott * dTextHeight1 + (ptVertices[2] - ptVertices[1]).normalize() * 0.4 * dTextHeight1; OdGeVector3d offs1 = (ptTextPosition - ptImageBoottomLeft) / topixel; double xoffset = offs1.x; double yoffset = imgSize.y - offs1.y - rasterWidth * sinus; //IO_TRACE("topixel=%f xoffset=%f, yoffset=%f imgSize.x=%f, imgSize.y=%f\n", topixel, xoffset, yoffset, imgSize.x, imgSize.y); std::vector datainv; datainv.resize(rasterWidth* rasterHeight * 3); unsigned char* datain = &datainv[0]; for (OdInt32 y = 0; y < rasterHeight; ++y) { for (OdInt32 x = 0; x < rasterWidth; ++x) { OdInt32 pixelPosLogo = (y * rasterWidth + x) * 4; unsigned char r = pData[pixelPosLogo + 0]; unsigned char g = pData[pixelPosLogo + 1]; unsigned char b = pData[pixelPosLogo + 2]; unsigned char a = pData[pixelPosLogo + 3]; OdInt32 A = (y * rasterWidth + x) * 3; datain[A + 0] = r; datain[A + 1] = g; datain[A + 2] = a; } } std::vector data3out; float ugol = OD_ATAN2(bott.y, bott.x); int rw= rasterWidth, rh = rasterHeight; unsigned char* dataout= &datainv[0]; if (ugol != 0) { CreateRotateBmp3(360.0 - ugol * 180.0 / OdaPI, rasterWidth, rasterHeight, datainv, rw, rh, data3out); if(!data3out.empty()) dataout = &data3out[0]; } for (OdInt32 y = 0; y < rh; ++y) { for (OdInt32 x = 0; x < rw; ++x) { OdInt32 P = (y * rw + x) * 3; unsigned char r = dataout[P + 0]; unsigned char g = dataout[P + 1]; unsigned char a = dataout[P + 2]; OdInt32 xt = xoffset + x; OdInt32 yt = yoffset + y; if (xt > 0 && xt < imgSize.x&&yt>0 && yt < imgSize.y) { OdInt32 A = (yt * imgSize.x + xt) * 4; if ( a != 0 ) { float alfa = a / 255.0f; float alfa1 = 1.0f - alfa; imgPixelData[A + 0] =(unsigned char)( imgPixelData[A + 0]*alfa1 + r*alfa); imgPixelData[A + 1] =(unsigned char)( imgPixelData[A + 1]*alfa1 + g*alfa); imgPixelData[A + 2] =(unsigned char)( imgPixelData[A + 2]*alfa1 + g*alfa); } } } } //for (OdInt32 y = 0; y < imgSize.y; ++y) //{ // for (OdInt32 x = 0; x < imgSize.x; ++x) // { // OdInt32 P = (y * imgSize.x + x) * 4; // unsigned char r = imgPixelData[P + 0]; // unsigned char g = imgPixelData[P + 1]; // unsigned char b = imgPixelData[P + 2]; // // ::SetPixel(hdc, x, y, RGB(r, g, b)); // } //} return eOk; } void GoogleBingToWGS84Mercator(double x, double y, double & lat, double & lon) { lon = (x / EarthRadius / OdaPI) * 180; lat = (y / EarthRadius / OdaPI) * 180; lat = 180/OdaPI * (2 * atan(exp(lat * OdaPI / 180)) - OdaPI / 2); } void WGS84ToGoogleBing(double lat, double lon, double & x, double & y) { x = lon * EarthRadius * OdaPI / 180; y = log(tan((90 + lat) * OdaPI / 360)) / (OdaPI / 180); y = y * EarthRadius * OdaPI / 180; } double Clip(double n, double minValue, double maxValue) { return odmin(odmax(n, minValue), maxValue); } unsigned int MapSize(int levelOfDetail) { return (unsigned int) 256 << levelOfDetail; } double GroundResolution(double latitude, int levelOfDetail) { latitude = Clip(latitude, MinLatitude, MaxLatitude); return cos(latitude * OdaPI / 180) * 2 * OdaPI * EarthRadius / MapSize(levelOfDetail); } double MapScale(double latitude, int levelOfDetail, int screenDpi) { return GroundResolution(latitude, levelOfDetail) * screenDpi / 0.0254; } void LatLongToPixelXY(double latitude, double longitude, int levelOfDetail, OdInt32 & pixelX, OdInt32 & pixelY) { latitude = Clip(latitude, MinLatitude, MaxLatitude); longitude = Clip(longitude, MinLongitude, MaxLongitude); double x = (longitude + 180) / 360; double sinLatitude = sin(latitude * OdaPI / 180); double y = 0.5 - log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * OdaPI); unsigned int mapSize = MapSize(levelOfDetail); pixelX = Clip(x * mapSize + 0.5, 0, mapSize - 1); pixelY = Clip(y * mapSize + 0.5, 0, mapSize - 1); } void PixelXYToLatLong(OdInt32 pixelX, OdInt32 pixelY, int levelOfDetail, double & latitude, double & longitude) { double mapSize = MapSize(levelOfDetail); double x = (Clip(pixelX, 0, mapSize - 1) / mapSize) - 0.5; double y = 0.5 - (Clip(pixelY, 0, mapSize - 1) / mapSize); latitude = 90 - 360 * atan(exp(-y * 2 * OdaPI)) / OdaPI; longitude = 360 * x; } void PixelXYToTileXY(OdInt32 pixelX, OdInt32 pixelY, OdInt32 & tileX, OdInt32 & tileY) { tileX = pixelX / 256; tileY = pixelY / 256; } void TileXYToPixelXY(OdInt32 tileX, OdInt32 tileY, OdInt32 & pixelX, OdInt32 & pixelY) { pixelX = tileX * 256; pixelY = tileY * 256; } OdAnsiString TileXYToQuadKey(OdInt32 tileX, OdInt32 tileY, int levelOfDetail) { OdAnsiString quadKey; for (int i = levelOfDetail; i > 0; --i) { char digit = '0'; int mask = 1 << (i - 1); if ((tileX & mask) != 0) { digit++; } if ((tileY & mask) != 0) { digit+=2; } quadKey += digit; } return quadKey; } void QuadKeyToTileXY(const OdString & quadKey, OdInt32 & tileX, OdInt32 & tileY, int & levelOfDetail) { tileX = tileY = 0; levelOfDetail = quadKey.getLength(); for (int i = levelOfDetail; i > 0; --i) { int mask = 1 << (i - 1); switch (quadKey[levelOfDetail - i]) { case '0': break; case '1': tileX |= mask; break; case '2': tileY |= mask; break; case '3': tileX |= mask; tileY |= mask; break; default: break; } } } void LatLongToTileXY(double latitude, double longitude, int levelOfDetail, OdInt32 & iTileX, OdInt32 & iTileY) { OdInt32 iPixelX, iPixelY; LatLongToPixelXY(latitude, longitude, levelOfDetail, iPixelX, iPixelY); PixelXYToTileXY(iPixelX, iPixelY, iTileX, iTileY); } void fillPixelData(OdBinaryData & pixelData, OdInt32 dataWidth, OdInt32 dataHeight, OdGiRasterImagePtr pRaster, OdInt32 posX, OdInt32 posY, bool transparency) { const OdUInt8 * pData = pRaster->scanLines(); OdInt32 rasterWidth = pRaster->pixelWidth(); OdInt32 rasterHeight = pRaster->pixelHeight(); OdInt32 yFirst = 0; OdInt32 yLast = rasterHeight; if (posY < 0) { yFirst = -posY; } if (posY + rasterHeight > dataHeight) { yLast = dataHeight - posY; } OdInt32 xFirst = 0; OdInt32 xLast = rasterWidth; if (posX < 0) { xFirst = -posX; } if (posX + rasterWidth > dataWidth) { xLast = dataWidth - posX; } if (xLast - xFirst <= 0) { return; } if (!transparency) { OdInt32 copySize = (xLast - xFirst) * sizeof(OdUInt8) * 4; for (OdInt32 y = yFirst; y < yLast; ++y) { memcpy(pixelData.asArrayPtr() + ((y + posY) * dataWidth + xFirst + posX) * 4, pData + ((y * rasterWidth) + xFirst) * 4, copySize); } } else { //TODO for (OdInt32 y = yFirst; y < yLast; ++y) { for (OdInt32 x = xFirst; x < xLast; ++x) { OdInt32 pixelPosA = ((y + posY) * dataWidth + x + posX) * 4; OdInt32 pixelPosB = ((y * rasterWidth) + x) * 4; /*if (pData[pixelPosB + 3] != 0) { memcpy(pixelData.asArrayPtr() + pixelPosA, pData + pixelPosB, sizeof(OdInt8) * 3); }*/ double alphaB = double(pData[pixelPosB + 3]) / 255.; for (int i = 0; i < 3; ++i) { double colorA = double(pixelData[pixelPosA + i]) / 255.; double colorB = double (pData[pixelPosB + i]) / 255.; pixelData[pixelPosA + i] = ((1. - alphaB) * colorA + alphaB * colorB) * 255.; } //pixelData[pixelPosA + 3] = pData[pixelPosB + 3]; } } } } OdResult getOptimalLOD(const OdDbGeoMap * pGeoMap, OdInt8 & LOD) { OdDbDatabasePtr pDb = pGeoMap->database(); OdDbViewportTablePtr pVt = pDb->getViewportTableId().safeOpenObject(); OdDbViewportTableRecordPtr pVp = pVt->getActiveViewportId().safeOpenObject(); OdGsView * pView = pVp->gsView(); if (pView == NULL) { return eNullPtr; } OdGsDCRect screenRect; pView->getViewport(screenRect); long viewportHeight = screenRect.m_min.y; long viewportWidth = screenRect.m_max.x; OdInt32 maxScreenSize = odmax(viewportWidth, viewportHeight); OdInt32 screenLod = 0; OdInt32 imageSize = 512; while (maxScreenSize > imageSize) { ++screenLod; imageSize *= 2; } OdGePoint3dArray ptVertices; pGeoMap->getVertices(ptVertices); OdDbObjectId objId; oddbGetGeoDataObjId(pGeoMap->database(), objId); OdDbGeoDataPtr pGeoData = objId.openObject(); if (pGeoData.isNull()) { return eNullPtr; } double mapSize = odmax(ptVertices[1].x - ptVertices[3].x, ptVertices[3].y - ptVertices[1].y); OdGePoint3d min; OdGePoint3d max; { //get min max cartersian points of global map by geo-extents OdDbGeoCoordinateSystemPtr pCs; OdDbGeoCoordinateSystem::create(pGeoData->coordinateSystem(), pCs); OdGeExtents2d extGeo; pCs->getGeodeticExtents(extGeo); OdGePoint3d minGeo(extGeo.minPoint().x, extGeo.minPoint().y, 0.); OdGePoint3d maxGeo(extGeo.maxPoint().x, extGeo.maxPoint().y, 0.); // minGeo and maxGeo could be out of geo-extents, // so we must correct their values, and create new extents from it correctGeoPt(minGeo); correctGeoPt(maxGeo); OdGeExtents3d geoExt; geoExt.addPoint(minGeo); geoExt.addPoint(maxGeo); pGeoData->transformFromLonLatAlt(geoExt.minPoint(), min); pGeoData->transformFromLonLatAlt(geoExt.maxPoint(), max); } double maxSize = odmax(fabs(max.x - min.x), fabs(max.y - min.y)); double percent = mapSize / maxSize; OdInt32 resultLod = 0; while (percent < 1.) { ++resultLod; percent *= 2.; } LOD = odmin(odmax(resultLod + screenLod, 1), 21); return eOk; } OdResult getImageSize(const OdDbGeoMap * pGeoMap, OdInt32 & width, OdInt32 & height) { OdGePoint3d BLpt = pGeoMap->imageBottomLeftPt(); double h = pGeoMap->imageHeight(); double w = pGeoMap->imageWidth(); //IO_TRACE("getImageSize w=%f, h=%f\n", w, h); OdInt32 LOD = odmin(odmax(pGeoMap->LOD() + pGeoMap->resolution(), 1), 21); OdGePoint3d ptUpperLeftLLA, ptBottomRightLLA; GoogleBingToWGS84Mercator(BLpt.x, BLpt.y, ptUpperLeftLLA.y, ptUpperLeftLLA.x); GoogleBingToWGS84Mercator(BLpt.x+w, BLpt.y+h, ptBottomRightLLA.y, ptBottomRightLLA.x); //get image width, height in pixels OdInt32 iPixelUpLeftX, iPixelUpLeftY, iPixelBotRightX, iPixelBotRightY; LatLongToPixelXY(ptUpperLeftLLA.y, ptUpperLeftLLA.x, LOD, iPixelUpLeftX, iPixelUpLeftY); LatLongToPixelXY(ptBottomRightLLA.y, ptBottomRightLLA.x, LOD, iPixelBotRightX, iPixelBotRightY); double dWidth = iPixelBotRightX - iPixelUpLeftX + 1; double dHeight = -iPixelBotRightY + iPixelUpLeftY + 1; ODA_ASSERT_ONCE(dWidth > 0); ODA_ASSERT_ONCE(dHeight > 0); // max ImageSize 2000x2000 double maxSize = odmax(dWidth, dHeight); if (maxSize > 2000) { dWidth = dWidth * 2000 / maxSize; dHeight = dHeight * 2000 / maxSize; } //but min ImageSize 50õ50, and it's more preferable double minSize = odmax(dWidth, dHeight); if (minSize < 50) { dWidth = dWidth * 50 / minSize; dHeight = dHeight * 50 / minSize; } width = dWidth; height = dHeight; //IO_TRACE("updateMapImage w=%d, h=%d\n", width, dHeight); return eOk; } OdResult OdDbGeoMapPEImpl::updateMapImage(OdDbGeoMap * pGeoMap, bool bReset) { if (pGeoMap == NULL) { return eNullPtr; } OdDbGeoMapFieldsPEPtr ext = OdDbGeoMap::desc()->getX(OdDbGeoMapFieldsPE::desc()); if (ext.isNull()) { return eNoInterface; } //if update failed, values must be restored ext->setIsOutOfDate(pGeoMap, false); // disable updateMapImage() in subClose() OdDbGeoMapPtr backupGeoMap = pGeoMap->clone(); OdResult status = eOk; if (bReset) { OdInt8 LOD; if(eOk != (status = getOptimalLOD(pGeoMap, LOD))) { pGeoMap->copyFrom(backupGeoMap); ext->setIsOutOfDate(pGeoMap, true); return status; } ext->setLOD(pGeoMap, LOD); ext->setResolution(pGeoMap, kOptimal); } OdInt32 nWidth, nHeight; if(eOk != (status = getImageSize(pGeoMap, nWidth, nHeight))) { pGeoMap->copyFrom(backupGeoMap); ext->setIsOutOfDate(pGeoMap, true); return status; } ext->setWidth(pGeoMap, nWidth); ext->setHeight(pGeoMap, nHeight); OdGePoint3dArray ptVertices; pGeoMap->getVertices(ptVertices); OdGePoint3d ptImageBottomLeft = pGeoMap->imageBottomLeftPt(); double dImageWidth = pGeoMap->imageWidth(); double dImageHeight = pGeoMap->imageHeight(); ext->setImageWidth(pGeoMap, dImageWidth); ext->setImageHeight(pGeoMap, dImageHeight); OdGeVector3d vU(dImageWidth / nWidth, 0., 0.); OdGeVector3d vV(0., dImageHeight / nHeight, 0.); ext->setvU(pGeoMap, vU); ext->setvV(pGeoMap, vV); OdGePoint2dArray ptClipBnd; ptClipBnd.resize(5); OdGeMatrix3d mat = pixelToModelTransform(ptImageBottomLeft, vU, vV, nHeight).inverse(); for (OdUInt32 i = 0; i < ptVertices.size(); ++i) { ptClipBnd[i] = (mat * ptVertices[i]).convert2d(); } ext->setPtClipBnd(pGeoMap, ptClipBnd); OdBinaryData PixelData; PixelData.resize(nWidth * nHeight * 4); OdStringArray strings; OdInt8 LOD; if (eOk != (status = getMap(pGeoMap, PixelData, strings, LOD))) { //restore geomap and set flag pGeoMap->copyFrom(backupGeoMap); ext->setIsOutOfDate(pGeoMap, true); } else { ext->setPixelData(pGeoMap, PixelData); ext->setStrings(pGeoMap, strings); ext->setLOD(pGeoMap, LOD); ext->setIsOutOfDate(pGeoMap, false); //TODO recalculate text height and pos, now it's caclulated by my gess only double dTextHeight = 853000. / pow (2., double(ext->getLOD(pGeoMap))); OdGePoint3d ptTextPosition = ptVertices[1] - (ptVertices[1] - ptVertices[0]).normalize() * 9.0 * dTextHeight + (ptVertices[2] - ptVertices[1]).normalize() * 2.0 * dTextHeight; ext->setTextHeight(pGeoMap, dTextHeight); ext->setPtTextPosition(pGeoMap, ptTextPosition); } return status; } float Point2Ang(int x, int y, float CentrX, float CentrY, float R) { float dx, dy, result; if (R != 0) { dx = x - CentrX; dy = y - CentrY; if (dx < 0) if (dy < 0) result = 360.f + 180.f * asin(dx / R) / OdaPI; else result = 180.f - 180.f * asin(dx / R) / OdaPI; else if (dy < 0) result = 180.f * asin(dx / R) / OdaPI; else result = 180.f - 180.f * asin(dx / R) / OdaPI; } else result = 0; return result; } inline float frac(const float x) { return x - floor(x); } int Domax(float x) { int result; if (frac(x) != 0) result = (int)(x) + 1; else result = (int)(x); return result; } int Doedin(float x) { int result; if (int(frac(x) * 10.0f) > 4.0f) result = (int)(x) + 1; else result = (int)(x); return result; } struct trgb { unsigned char B, G, R; }; struct expoint { float X, Y; }; struct excol { float R, G, B; float CAr; //Covered Area }; void CreateRotateBmp3(float ugol, int g_Width, int g_Height, const std::vector& datainv, int& rw, int& rh, std::vector& data3out) { float CX = 0, CY = 0, delt = 0; float deltaX, deltaY, x1, x2, x3, x4, y1, y2, y3, y4, sx1, sx2, sx3, sx4, sy1, sy2, sy3, sy4, s1, s2, s3, s4, s5, s6, s7, s8, s9, dx1, dx3, dx4, dy1, dy2, dy3, dy4, tgAd2, tgBd2, sinB, cosB, sinBucosBd2, cosAu2, cosBu2, triS; int i, j, ix1, ix2, ix3, ix4, iy1, iy2, iy3, iy4, eR, Ge, Be; std::vector< expoint> row; std::vector < std::vector < excol> > res; int FonR = 0; int FonG = 0; int FonB = 0; float CXpCY = CX + CY; float CXpCX = CX + CX; float CYpCY = CY + CY; float CXmCY = CX - CY; if (ugol >= 360.f) ugol = ugol - 360.f * (int)(ugol / 360.f); if (ugol == 0) { return; } int U90 = (int)(ugol / 90.f); // ì0, 1, 2, 3 ugol = ugol - U90 * 90.0f; // 0° -- 90° float R = sqrt(CX*CX + CY * CY); float ug = Point2Ang(0, 0, CX, CY, R) + ugol; float vlx = CX + R * sin(OdaPI*ug / 180.f); float vly = CY - R * cos(OdaPI*ug / 180.f); ug = ugol + 45.f; R = sqrt(0.5f); float A = R * sin(OdaPI*ug / 180.f); float B = R * cos(OdaPI*ug / 180.f); float dx = A + B; float dy = A - B; float B2 = B + B; float A2 = A + A; row.resize(g_Width + 1); for (i = 0; i <= g_Width; i++) { row[i].X = vlx + dx * i; row[i].Y = vly + dy * i; } R = sqrt((CX - g_Width)*(CX - g_Width) + (CY - g_Height)*(CY - g_Height)); B = CY - R * cos(OdaPI*(Point2Ang(g_Width, g_Height, CX, CY, R) + ugol) / 180.f); //y2 switch (U90) { case 0: // 90° deltaX = fabs(vlx - g_Height * dy); //x3 deltaY = fabs(vly); //y4 rw = Domax(row[g_Width].X + deltaX); rh = Domax(B + deltaY); break; case 1: // 180° deltaX = fabs(CXpCY - B); deltaY = fabs(vlx - g_Height * dy - CXmCY); rw = Domax(CXpCY - vly + deltaX); rh = Domax(row[g_Width].X - CXmCY + deltaY); break; case 2: // 270° deltaX = fabs(CXpCX - row[g_Width].X); deltaY = fabs(CYpCY - B); rw = Domax(CXpCX - vlx + g_Height * dy + deltaX); rh = Domax(CYpCY - vly + deltaY); break; case 3: // 360° deltaX = fabs(vly + CXmCY); deltaY = fabs(CXpCY - row[g_Width].X); rw = Domax(CXmCY + B + deltaX); rh = Domax(CXpCY - vlx + g_Height * dy + deltaY); break; } int component = 3; data3out.resize(rw*rh * component); unsigned char* data3 = &data3out[0]; const unsigned char * datain = &datainv[0]; if (ugol == 0) { switch (U90) { case 1: //90° for (i = 0; i < g_Height; i++) for (j = 0; j < g_Width; j++) { unsigned char* out = data3 + (j * g_Width + (g_Height - 1 - i))*component; const unsigned char* in = datain + (i * g_Width + j)*component; *(out + 0) = *(in + 0); *(out + 1) = *(in + 1); *(out + 2) = *(in + 2); } break; case 2: //180° for (i = 0; i < g_Height; i++) for (j = 0; j < g_Width; j++) { unsigned char* out = data3 + ((g_Height - 1 - i) * g_Width + (g_Width - 1 - j))*component; const unsigned char* in = datain + (i * g_Width + j)*component; *(out + 0) = *(in + 0); *(out + 1) = *(in + 1); *(out + 2) = *(in + 2); } break; case 3: //270° for (i = 0; i < g_Height; i++) for (j = 0; j < g_Width; j++) { // unsigned char* out = data3 + ((g_Width - 1 - j) * g_Width + i)*component; // const unsigned char* in = datain + (i * g_Width + j)*component; int out = ((g_Height - 1 - j) * g_Width + i)*component; int in = (i * g_Width + j)*component; data3[out] = datain[in]; data3[out+1] = datain[in+1]; data3[out+2] = datain[in+2]; //*(out + 0) = *(in + 0); //*(out + 1) = *(in + 1); //*(out + 2) = *(in + 2); } break; } return; } res.resize(rh); for (int i = 0; i != rh; i++) res[i].resize(rw); tgBd2 = tan(OdaPI*(90 - ugol) / 180) / 2; tgAd2 = tan(OdaPI*ugol / 180) / 2; sinB = sin(OdaPI*(90 - ugol) / 180); cosB = cos(OdaPI*(90 - ugol) / 180); cosAu2 = cos(OdaPI*ugol / 180) * 2; cosBu2 = cos(OdaPI*(90 - ugol) / 180) * 2; triS = cos(OdaPI*ugol / 180)*sin(OdaPI*ugol / 180) / 2; sinBucosBd2 = sin(OdaPI*(90 - ugol) / 180)*cos(OdaPI*(90 - ugol) / 180) * 2; const unsigned char* addrin = &datain[0]; for (j = 0; j < g_Height; j++) { x2 = vlx - (j + 1)*dy; y2 = vly + (j + 1)*dx; for (i = 0; i < g_Width; i++) { x4 = row[i].X; y4 = row[i].Y; x1 = row[i + 1].X; y1 = row[i + 1].Y; x3 = x2; y3 = y2; row[i].X = x2; row[i].Y = y2; x2 = x4 + B2; y2 = y4 + A2; eR = *(addrin + 0); Ge = *(addrin + 1); Be = *(addrin + 2); addrin += component; switch (U90) { case 0: // 0° sx1 = x1 + deltaX; sy1 = y1 + deltaY; sx2 = x2 + deltaX; sy2 = y2 + deltaY; sx3 = x3 + deltaX; sy3 = y3 + deltaY; sx4 = x4 + deltaX; sy4 = y4 + deltaY; break; case 1: //90° sx1 = CXpCY - y4 + deltaX; sy1 = x4 - CXmCY + deltaY; sx2 = CXpCY - y1 + deltaX; sy2 = x1 - CXmCY + deltaY; sx3 = CXpCY - y2 + deltaX; sy3 = x2 - CXmCY + deltaY; sx4 = CXpCY - y3 + deltaX; sy4 = x3 - CXmCY + deltaY; //IO_TRACE("sy2=%f\n", sy2); break; case 2: //180° sx1 = CXpCX - x3 + deltaX; sy1 = CYpCY - y3 + deltaY; sx2 = CXpCX - x4 + deltaX; sy2 = CYpCY - y4 + deltaY; sx3 = CXpCX - x1 + deltaX; sy3 = CYpCY - y1 + deltaY; sx4 = CXpCX - x2 + deltaX; sy4 = CYpCY - y2 + deltaY; //IO_TRACE("sy2=%f\n", sy2); break; case 3: //270° sx1 = CXmCY + y2 + deltaX; sy1 = CXpCY - x2 + deltaY; sx2 = CXmCY + y3 + deltaX; sy2 = CXpCY - x3 + deltaY; sx3 = CXmCY + y4 + deltaX; sy3 = CXpCY - x4 + deltaY; sx4 = CXmCY + y1 + deltaX; sy4 = CXpCY - x1 + deltaY; break; }; ix1 = (int)(sx1); iy1 = (int)(sy1); ix2 = (int)(sx2); iy2 = (int)(sy2); ix3 = (int)(sx3); iy3 = (int)(sy3); ix4 = (int)(sx4); iy4 = (int)(sy4); if (iy3 == iy2) if (iy4 == iy1) if (ix4 == ix3) if (ix1 == ix2) { //implementation option 1 dy2 = frac(sy2); dx3 = 1.0f - frac(sx3); dy3 = frac(sy3); dx4 = 1.0f - frac(sx4); dy4 = 1.0f - frac(sy4); s3 = dx3 * dy3 + (dx3*dx3 - dy3 * dy3)*tgAd2; s4 = dx4 * dy4 + (dy4*dy4 - dx4 * dx4)*tgAd2; s1 = 0.5f + (dy4 - dy2) / cosAu2; s2 = 1.0f - s1 - s3; s1 = s1 - s4; res[iy1][ix1].R = res[iy1][ix1].R + eR * s1; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s1; res[iy1][ix1].B = res[iy1][ix1].B + Be * s1; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s1; res[iy2][ix2].R = res[iy2][ix2].R + eR * s2; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s2; res[iy2][ix2].B = res[iy2][ix2].B + Be * s2; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s2; res[iy3][ix3].R = res[iy3][ix3].R + eR * s3; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s3; res[iy3][ix3].B = res[iy3][ix3].B + Be * s3; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s3; res[iy4][ix4].R = res[iy4][ix4].R + eR * s4; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s4; res[iy4][ix4].B = res[iy4][ix4].B + Be * s4; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s4; } else { //implementation option 15 dx1 = frac(sx1); dy2 = frac(sy2); dy4 = 1 - frac(sy4); s4 = dx1 / cosB + dy2 / sinB - 1; s4 = s4 * s4*triS; res[iy2][ix1].R = res[iy2][ix1].R + eR * s4; res[iy2][ix1].G = res[iy2][ix1].G + Ge * s4; res[iy2][ix1].B = res[iy2][ix1].B + Be * s4; res[iy2][ix1].CAr = res[iy2][ix1].CAr + s4; s2 = dx1 * dx1 / sinBucosBd2 - s4; s1 = 0.5f + (dy4 - dy2) / cosAu2; s3 = 1.0f - s1 - s4; s1 = s1 - s2; res[iy4][ix4].R = res[iy4][ix4].R + eR * s1; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s1; res[iy4][ix4].B = res[iy4][ix4].B + Be * s1; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s1; res[iy1][ix1].R = res[iy1][ix1].R + eR * s2; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s2; res[iy1][ix1].B = res[iy1][ix1].B + Be * s2; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s2; res[iy2][ix2].R = res[iy2][ix2].R + eR * s3; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s3; res[iy2][ix2].B = res[iy2][ix2].B + Be * s3; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s3; } else if (ix1 == ix2) { //implementation option 11 dy2 = frac(sy2); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s1 = dx3 / cosB + dy4 / sinB - 1.0f; s1 = s1 * s1*triS; res[iy4][ix3].R = res[iy4][ix3].R + eR * s1; res[iy4][ix3].G = res[iy4][ix3].G + Ge * s1; res[iy4][ix3].B = res[iy4][ix3].B + Be * s1; res[iy4][ix3].CAr = res[iy4][ix3].CAr + s1; s3 = dx3 * dx3 / sinBucosBd2 - s1; s2 = 0.5f + (dy4 - dy2) / cosAu2; s4 = 1.0f - s2 - s3; s2 = s2 - s1; res[iy4][ix4].R = res[iy4][ix4].R + eR * s2; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s2; res[iy4][ix4].B = res[iy4][ix4].B + Be * s2; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s2; res[iy3][ix3].R = res[iy3][ix3].R + eR * s3; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s3; res[iy3][ix3].B = res[iy3][ix3].B + Be * s3; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s3; res[iy2][ix2].R = res[iy2][ix2].R + eR * s4; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s4; res[iy2][ix2].B = res[iy2][ix2].B + Be * s4; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s4; } else { //implementation option 4 dx1 = frac(sx1); dy2 = frac(sy2); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s1 = dx3 / cosB + dy4 / sinB - 1; if (s1 > 0) { s1 = s1 * s1*triS; res[iy4][ix3].R = res[iy4][ix3].R + eR * s1; res[iy4][ix3].G = res[iy4][ix3].G + Ge * s1; res[iy4][ix3].B = res[iy4][ix3].B + Be * s1; res[iy4][ix3].CAr = res[iy4][ix3].CAr + s1; } else s1 = 0; s6 = dx1 / cosB + dy2 / sinB - 1; if (s6 > 0) { s6 = s6 * s6*triS; res[iy2][ix1].R = res[iy2][ix1].R + eR * s6; res[iy2][ix1].G = res[iy2][ix1].G + Ge * s6; res[iy2][ix1].B = res[iy2][ix1].B + Be * s6; res[iy2][ix1].CAr = res[iy2][ix1].CAr + s6; } else s6 = 0; s4 = dx3 * dx3 / sinBucosBd2 - s1; s3 = dx1 * dx1 / sinBucosBd2 - s6; s2 = 0.5f + (dy4 - dy2) / cosAu2; s5 = 1 - s2 - s4 - s6; s2 = s2 - s1 - s3; res[iy4][ix4].R = res[iy4][ix4].R + eR * s2; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s2; res[iy4][ix4].B = res[iy4][ix4].B + Be * s2; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s2; res[iy3][ix3].R = res[iy3][ix3].R + eR * s4; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s4; res[iy3][ix3].B = res[iy3][ix3].B + Be * s4; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s4; res[iy2][ix2].R = res[iy2][ix2].R + eR * s5; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s5; res[iy2][ix2].B = res[iy2][ix2].B + Be * s5; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s5; res[iy1][ix1].R = res[iy1][ix1].R + eR * s3; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s3; res[iy1][ix1].B = res[iy1][ix1].B + Be * s3; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s3; } else if (ix4 == ix2) if (ix4 == ix1) { //implementation option 10 dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s1 = dx3 / cosB + dy4 / sinB - 1; s1 = s1 * s1*triS; res[iy4][ix3].R = res[iy4][ix3].R + eR * s1; res[iy4][ix3].G = res[iy4][ix3].G + Ge * s1; res[iy4][ix3].B = res[iy4][ix3].B + Be * s1; res[iy4][ix3].CAr = res[iy4][ix3].CAr + s1; s2 = dy4 * dy4 / sinBucosBd2 - s1; s3 = dx3 * dx3 / sinBucosBd2 - s1; s4 = 1 - s1 - s2 - s3; res[iy4][ix4].R = res[iy4][ix4].R + eR * s2; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s2; res[iy4][ix4].B = res[iy4][ix4].B + Be * s2; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s2; res[iy3][ix3].R = res[iy3][ix3].R + eR * s3; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s3; res[iy3][ix3].B = res[iy3][ix3].B + Be * s3; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s3; res[iy3][ix4].R = res[iy3][ix4].R + eR * s4; res[iy3][ix4].G = res[iy3][ix4].G + Ge * s4; res[iy3][ix4].B = res[iy3][ix4].B + Be * s4; res[iy3][ix4].CAr = res[iy3][ix4].CAr + s4; } else if (ix3 == ix2) { //implementation option 17 dx1 = frac(sx1); dy4 = 1 - frac(sy4); s2 = dx1 / sinB + dy4 / cosB - 1; s2 = s2 * s2*triS; res[iy4][ix1].R = res[iy4][ix1].R + eR * s2; res[iy4][ix1].G = res[iy4][ix1].G + Ge * s2; res[iy4][ix1].B = res[iy4][ix1].B + Be * s2; res[iy4][ix1].CAr = res[iy4][ix1].CAr + s2; s1 = dy4 * dy4 / sinBucosBd2 - s2; s4 = dx1 * dx1 / sinBucosBd2 - s2; s3 = 1 - s1 - s2 - s4; res[iy4][ix4].R = res[iy4][ix4].R + eR * s1; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s1; res[iy4][ix4].B = res[iy4][ix4].B + Be * s1; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s1; res[iy1][ix1].R = res[iy1][ix1].R + eR * s4; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s4; res[iy1][ix1].B = res[iy1][ix1].B + Be * s4; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s4; res[iy1][ix4].R = res[iy1][ix4].R + eR * s3; res[iy1][ix4].G = res[iy1][ix4].G + Ge * s3; res[iy1][ix4].B = res[iy1][ix4].B + Be * s3; res[iy1][ix4].CAr = res[iy1][ix4].CAr + s3; } else { //implementation option 5 dx1 = frac(sx1); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s1 = dx3 / cosB + dy4 / sinB - 1; if (s1 > 0) { s1 = s1 * s1*triS; res[iy4][ix3].R = res[iy4][ix3].R + eR * s1; res[iy4][ix3].G = res[iy4][ix3].G + Ge * s1; res[iy4][ix3].B = res[iy4][ix3].B + Be * s1; res[iy4][ix3].CAr = res[iy4][ix3].CAr + s1; } else s1 = 0; s3 = dx1 / sinB + dy4 / cosB - 1; if (s3 > 0) { s3 = s3 * s3*triS; res[iy4][ix1].R = res[iy4][ix1].R + eR * s3; res[iy4][ix1].G = res[iy4][ix1].G + Ge * s3; res[iy4][ix1].B = res[iy4][ix1].B + Be * s3; res[iy4][ix1].CAr = res[iy4][ix1].CAr + s3; } else s3 = 0; s2 = dy4 * dy4 / sinBucosBd2; s4 = dx3 * dx3 / sinBucosBd2 - s1; s6 = dx1 * dx1 / sinBucosBd2 - s3; s5 = 1 - s2 - s4 - s6; s2 = s2 - s1 - s3; res[iy4][ix4].R = res[iy4][ix4].R + eR * s2; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s2; res[iy4][ix4].B = res[iy4][ix4].B + Be * s2; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s2; res[iy3][ix3].R = res[iy3][ix3].R + eR * s4; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s4; res[iy3][ix3].B = res[iy3][ix3].B + Be * s4; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s4; res[iy1][ix1].R = res[iy1][ix1].R + eR * s6; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s6; res[iy1][ix1].B = res[iy1][ix1].B + Be * s6; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s6; res[iy3][ix4].R = res[iy3][ix4].R + eR * s5; res[iy3][ix4].G = res[iy3][ix4].G + Ge * s5; res[iy3][ix4].B = res[iy3][ix4].B + Be * s5; res[iy3][ix4].CAr = res[iy3][ix4].CAr + s5; } else if (ix4 == ix3) { //implementation option 16 dx1 = frac(sx1); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s2 = dx1 / sinB + dy4 / cosB - 1; s2 = s2 * s2*triS; res[iy4][ix1].R = res[iy4][ix1].R + eR * s2; res[iy4][ix1].G = res[iy4][ix1].G + Ge * s2; res[iy4][ix1].B = res[iy4][ix1].B + Be * s2; res[iy4][ix1].CAr = res[iy4][ix1].CAr + s2; s1 = dy4 * dy4 / sinBucosBd2 - s2; s4 = 0.5f + (dx1 - dx3) / cosAu2; s3 = 1 - s4 - s1; s4 = s4 - s2; res[iy4][ix4].R = res[iy4][ix4].R + eR * s1; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s1; res[iy4][ix4].B = res[iy4][ix4].B + Be * s1; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s1; res[iy3][ix3].R = res[iy3][ix3].R + eR * s3; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s3; res[iy3][ix3].B = res[iy3][ix3].B + Be * s3; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s3; res[iy1][ix1].R = res[iy1][ix1].R + eR * s4; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s4; res[iy1][ix1].B = res[iy1][ix1].B + Be * s4; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s4; } else { //implementation option 12 dx1 = frac(sx1); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s1 = dx3 / cosB + dy4 / sinB - 1; s1 = s1 * s1*triS; res[iy4][ix3].R = res[iy4][ix3].R + eR * s1; res[iy4][ix3].G = res[iy4][ix3].G + Ge * s1; res[iy4][ix3].B = res[iy4][ix3].B + Be * s1; res[iy4][ix3].CAr = res[iy4][ix3].CAr + s1; s2 = dy4 * dy4 / sinBucosBd2 - s1; s3 = 0.5f + (dx3 - dx1) / cosBu2; s4 = 1 - s3 - s2; s3 = s3 - s1; res[iy4][ix4].R = res[iy4][ix4].R + eR * s2; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s2; res[iy4][ix4].B = res[iy4][ix4].B + Be * s2; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s2; res[iy3][ix3].R = res[iy3][ix3].R + eR * s3; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s3; res[iy3][ix3].B = res[iy3][ix3].B + Be * s3; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s3; res[iy1][ix1].R = res[iy1][ix1].R + eR * s4; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s4; res[iy1][ix1].B = res[iy1][ix1].B + Be * s4; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s4; } else if (iy3 == iy4) if (ix3 == ix2) if (ix4 == ix1) if (iy2 == iy1) { //implementation option 2 dx4 = frac(sx4); dy2 = frac(sy2); dy4 = 1 - frac(sy4); dx1 = frac(sx1); dy1 = frac(sy1); s4 = dx4 * dy4 + (dy4*dy4 - dx4 * dx4)*tgBd2; s1 = dx1 * dy1 + (dx1*dx1 - dy1 * dy1)*tgBd2; s3 = 0.5f + (dy4 - dy2) / cosBu2; s2 = 1 - s3 - s1; s3 = s3 - s4; res[iy1][ix1].R = res[iy1][ix1].R + eR * s1; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s1; res[iy1][ix1].B = res[iy1][ix1].B + Be * s1; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s1; res[iy2][ix2].R = res[iy2][ix2].R + eR * s2; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s2; res[iy2][ix2].B = res[iy2][ix2].B + Be * s2; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s2; res[iy3][ix3].R = res[iy3][ix3].R + eR * s3; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s3; res[iy3][ix3].B = res[iy3][ix3].B + Be * s3; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s3; res[iy4][ix4].R = res[iy4][ix4].R + eR * s4; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s4; res[iy4][ix4].B = res[iy4][ix4].B + Be * s4; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s4; } else { //implementation option 13 dx1 = frac(sx1); dy2 = frac(sy2); dx3 = 1 - frac(sx3); s4 = dx1 / cosB + dy2 / sinB - 1; s4 = s4 * s4*triS; res[iy2][ix1].R = res[iy2][ix1].R + eR * s4; res[iy2][ix1].G = res[iy2][ix1].G + Ge * s4; res[iy2][ix1].B = res[iy2][ix1].B + Be * s4; res[iy2][ix1].CAr = res[iy2][ix1].CAr + s4; s3 = dy2 * dy2 / sinBucosBd2 - s4; s1 = 0.5f + (dx3 - dx1) / cosBu2; s2 = 1 - s1 - s4; s1 = s1 - s3; res[iy3][ix3].R = res[iy3][ix3].R + eR * s1; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s1; res[iy3][ix3].B = res[iy3][ix3].B + Be * s1; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s1; res[iy2][ix2].R = res[iy2][ix2].R + eR * s3; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s3; res[iy2][ix2].B = res[iy2][ix2].B + Be * s3; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s3; res[iy1][ix1].R = res[iy1][ix1].R + eR * s2; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s2; res[iy1][ix1].B = res[iy1][ix1].B + Be * s2; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s2; } else if (iy2 == iy1) { //implementation option 18 dx1 = frac(sx1); dy2 = frac(sy2); dy4 = 1 - frac(sy4); s2 = dx1 / sinB + dy4 / cosB - 1; s2 = s2 * s2*triS; res[iy4][ix1].R = res[iy4][ix1].R + eR * s2; res[iy4][ix1].G = res[iy4][ix1].G + Ge * s2; res[iy4][ix1].B = res[iy4][ix1].B + Be * s2; res[iy4][ix1].CAr = res[iy4][ix1].CAr + s2; s4 = dx1 * dx1 / sinBucosBd2 - s2; s1 = 0.5f + (dy4 - dy2) / cosBu2; s3 = 1.0f - s1 - s4; s1 = s1 - s2; res[iy4][ix4].R = res[iy4][ix4].R + eR * s1; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s1; res[iy4][ix4].B = res[iy4][ix4].B + Be * s1; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s1; res[iy2][ix2].R = res[iy2][ix2].R + eR * s3; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s3; res[iy2][ix2].B = res[iy2][ix2].B + Be * s3; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s3; res[iy1][ix1].R = res[iy1][ix1].R + eR * s4; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s4; res[iy1][ix1].B = res[iy1][ix1].B + Be * s4; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s4; } else { //implementation option 14 dx1 = frac(sx1); dy2 = frac(sy2); s4 = dx1 / cosB + dy2 / sinB - 1; s4 = s4 * s4*triS; res[iy2][ix1].R = res[iy2][ix1].R + eR * s4; res[iy2][ix1].G = res[iy2][ix1].G + Ge * s4; res[iy2][ix1].B = res[iy2][ix1].B + Be * s4; res[iy2][ix1].CAr = res[iy2][ix1].CAr + s4; s2 = dx1 * dx1 / sinBucosBd2 - s4; s3 = dy2 * dy2 / sinBucosBd2 - s4; s1 = 1 - s2 - s3 - s4; res[iy1][ix1].R = res[iy1][ix1].R + eR * s2; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s2; res[iy1][ix1].B = res[iy1][ix1].B + Be * s2; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s2; res[iy2][ix2].R = res[iy2][ix2].R + eR * s3; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s3; res[iy2][ix2].B = res[iy2][ix2].B + Be * s3; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s3; res[iy1][ix2].R = res[iy1][ix2].R + eR * s1; res[iy1][ix2].G = res[iy1][ix2].G + Ge * s1; res[iy1][ix2].B = res[iy1][ix2].B + Be * s1; res[iy1][ix2].CAr = res[iy1][ix2].CAr + s1; } else if (ix2 == ix1) if (ix3 == ix4) { //implementation option 9 dx1 = frac(sx1); dy2 = frac(sy2); dx3 = 1 - frac(sx3); s3 = dx3 / sinB + dy2 / cosB - 1; s3 = s3 * s3*triS; res[iy2][ix3].R = res[iy2][ix3].R + eR * s3; res[iy2][ix3].G = res[iy2][ix3].G + Ge * s3; res[iy2][ix3].B = res[iy2][ix3].B + Be * s3; res[iy2][ix3].CAr = res[iy2][ix3].CAr + s3; s4 = dy2 * dy2 / sinBucosBd2 - s3; s2 = 0.5f + (dx1 - dx3) / cosAu2; s1 = 1.0f - s2 - s3; s2 = s2 - s4; res[iy2][ix2].R = res[iy2][ix2].R + eR * s4; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s4; res[iy2][ix2].B = res[iy2][ix2].B + Be * s4; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s4; res[iy1][ix1].R = res[iy1][ix1].R + eR * s2; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s2; res[iy1][ix1].B = res[iy1][ix1].B + Be * s2; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s2; res[iy3][ix3].R = res[iy3][ix3].R + eR * s1; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s1; res[iy3][ix3].B = res[iy3][ix3].B + Be * s1; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s1; } else if (iy3 == iy1) { //implementation option 8 dy2 = frac(sy2); dx3 = 1 - frac(sx3); s3 = dx3 / sinB + dy2 / cosB - 1; s3 = s3 * s3*triS; res[iy2][ix3].R = res[iy2][ix3].R + eR * s3; res[iy2][ix3].G = res[iy2][ix3].G + Ge * s3; res[iy2][ix3].B = res[iy2][ix3].B + Be * s3; res[iy2][ix3].CAr = res[iy2][ix3].CAr + s3; s1 = dx3 * dx3 / sinBucosBd2 - s3; s4 = dy2 * dy2 / sinBucosBd2 - s3; s2 = 1 - s1 - s3 - s4; res[iy3][ix3].R = res[iy3][ix3].R + eR * s1; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s1; res[iy3][ix3].B = res[iy3][ix3].B + Be * s1; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s1; res[iy2][ix2].R = res[iy2][ix2].R + eR * s4; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s4; res[iy2][ix2].B = res[iy2][ix2].B + Be * s4; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s4; res[iy3][ix2].R = res[iy3][ix2].R + eR * s2; res[iy3][ix2].G = res[iy3][ix2].G + Ge * s2; res[iy3][ix2].B = res[iy3][ix2].B + Be * s2; res[iy3][ix2].CAr = res[iy3][ix2].CAr + s2; } else { //implementation option 7 dy2 = frac(sy2); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s3 = dx3 / sinB + dy2 / cosB - 1; s3 = s3 * s3*triS; res[iy2][ix3].R = res[iy2][ix3].R + eR * s3; res[iy2][ix3].G = res[iy2][ix3].G + Ge * s3; res[iy2][ix3].B = res[iy2][ix3].B + Be * s3; res[iy2][ix3].CAr = res[iy2][ix3].CAr + s3; s1 = dx3 * dx3 / sinBucosBd2 - s3; s2 = 0.5f + (dy4 - dy2) / cosBu2; s4 = 1.0f - s2 - s3; s2 = s2 - s1; res[iy3][ix3].R = res[iy3][ix3].R + eR * s1; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s1; res[iy3][ix3].B = res[iy3][ix3].B + Be * s1; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s1; res[iy4][ix4].R = res[iy4][ix4].R + eR * s2; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s2; res[iy4][ix4].B = res[iy4][ix4].B + Be * s2; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s2; res[iy2][ix4].R = res[iy2][ix4].R + eR * s4; res[iy2][ix4].G = res[iy2][ix4].G + Ge * s4; res[iy2][ix4].B = res[iy2][ix4].B + Be * s4; res[iy2][ix4].CAr = res[iy2][ix4].CAr + s4; } else if (iy3 == iy1) { //implementation option 6 dx1 = frac(sx1); dy2 = frac(sy2); dx3 = 1 - frac(sx3); s4 = dx3 / sinB + dy2 / cosB - 1; if (s4 > 0) { s4 = s4 * s4*triS; res[iy2][ix3].R = res[iy2][ix3].R + eR * s4; res[iy2][ix3].G = res[iy2][ix3].G + Ge * s4; res[iy2][ix3].B = res[iy2][ix3].B + Be * s4; res[iy2][ix3].CAr = res[iy2][ix3].CAr + s4; } else s4 = 0; s6 = dx1 / cosB + dy2 / sinB - 1; if (s6 > 0) { s6 = s6 * s6*triS; res[iy2][ix1].R = res[iy2][ix1].R + eR * s6; res[iy2][ix1].G = res[iy2][ix1].G + Ge * s6; res[iy2][ix1].B = res[iy2][ix1].B + Be * s6; res[iy2][ix1].CAr = res[iy2][ix1].CAr + s6; } else s6 = 0; s1 = dx3 * dx3 / sinBucosBd2 - s4; s3 = dx1 * dx1 / sinBucosBd2 - s6; s5 = dy2 * dy2 / sinBucosBd2; s2 = 1 - s1 - s3 - s5; s5 = s5 - s4 - s6; res[iy3][ix3].R = res[iy3][ix3].R + eR * s1; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s1; res[iy3][ix3].B = res[iy3][ix3].B + Be * s1; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s1; res[iy1][ix1].R = res[iy1][ix1].R + eR * s3; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s3; res[iy1][ix1].B = res[iy1][ix1].B + Be * s3; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s3; res[iy2][ix2].R = res[iy2][ix2].R + eR * s5; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s5; res[iy2][ix2].B = res[iy2][ix2].B + Be * s5; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s5; res[iy3][ix2].R = res[iy3][ix2].R + eR * s2; res[iy3][ix2].G = res[iy3][ix2].G + Ge * s2; res[iy3][ix2].B = res[iy3][ix2].B + Be * s2; res[iy3][ix2].CAr = res[iy3][ix2].CAr + s2; } else { //implementation option 3 dx1 = frac(sx1); dy2 = frac(sy2); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s4 = dx3 / sinB + dy2 / cosB - 1; if (s4 > 0) { s4 = s4 * s4*triS; res[iy2][ix3].R = res[iy2][ix3].R + eR * s4; res[iy2][ix3].G = res[iy2][ix3].G + Ge * s4; res[iy2][ix3].B = res[iy2][ix3].B + Be * s4; res[iy2][ix3].CAr = res[iy2][ix3].CAr + s4; } else s4 = 0; s3 = dx1 / sinB + dy4 / cosB - 1; if (s3 > 0) { s3 = s3 * s3*triS; res[iy4][ix1].R = res[iy4][ix1].R + eR * s3; res[iy4][ix1].G = res[iy4][ix1].G + Ge * s3; res[iy4][ix1].B = res[iy4][ix1].B + Be * s3; res[iy4][ix1].CAr = res[iy4][ix1].CAr + s3; } else s3 = 0; s1 = dx3 * dx3 / sinBucosBd2 - s4; s6 = dx1 * dx1 / sinBucosBd2 - s3; s2 = 0.5f + (dy4 - dy2) / cosBu2; s5 = 1.0f - s2 - s4 - s6; s2 = s2 - s1 - s3; res[iy1][ix1].R = res[iy1][ix1].R + eR * s6; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s6; res[iy1][ix1].B = res[iy1][ix1].B + Be * s6; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s6; res[iy2][ix2].R = res[iy2][ix2].R + eR * s5; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s5; res[iy2][ix2].B = res[iy2][ix2].B + Be * s5; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s5; res[iy3][ix3].R = res[iy3][ix3].R + eR * s1; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s1; res[iy3][ix3].B = res[iy3][ix3].B + Be * s1; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s1; res[iy4][ix4].R = res[iy4][ix4].R + eR * s2; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s2; res[iy4][ix4].B = res[iy4][ix4].B + Be * s2; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s2; } else if (ix4 == ix2) if (ix3 == ix4) { //implementation option 21 dx1 = frac(sx1); dy2 = frac(sy2); dy4 = 1 - frac(sy4); s2 = dx1 / sinB + dy4 / cosB - 1; if (s2 > 0) { s2 = s2 * s2*triS; res[iy4][ix1].R = res[iy4][ix1].R + eR * s2; res[iy4][ix1].G = res[iy4][ix1].G + Ge * s2; res[iy4][ix1].B = res[iy4][ix1].B + Be * s2; res[iy4][ix1].CAr = res[iy4][ix1].CAr + s2; } else s2 = 0; s6 = dx1 / cosB + dy2 / sinB - 1; if (s6 > 0) { s6 = s6 * s6*triS; res[iy2][ix1].R = res[iy2][ix1].R + eR * s6; res[iy2][ix1].G = res[iy2][ix1].G + Ge * s6; res[iy2][ix1].B = res[iy2][ix1].B + Be * s6; res[iy2][ix1].CAr = res[iy2][ix1].CAr + s6; } else s6 = 0; s1 = dy4 * dy4 / sinBucosBd2 - s2; s5 = dy2 * dy2 / sinBucosBd2 - s6; s4 = dx1 * dx1 / sinBucosBd2; s3 = 1 - s4 - s1 - s5; s4 = s4 - s2 - s6; res[iy4][ix4].R = res[iy4][ix4].R + eR * s1; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s1; res[iy4][ix4].B = res[iy4][ix4].B + Be * s1; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s1; res[iy1][ix1].R = res[iy1][ix1].R + eR * s4; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s4; res[iy1][ix1].B = res[iy1][ix1].B + Be * s4; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s4; res[iy2][ix2].R = res[iy2][ix2].R + eR * s5; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s5; res[iy2][ix2].B = res[iy2][ix2].B + Be * s5; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s5; res[iy1][ix2].R = res[iy1][ix2].R + eR * s3; res[iy1][ix2].G = res[iy1][ix2].G + Ge * s3; res[iy1][ix2].B = res[iy1][ix2].B + Be * s3; res[iy1][ix2].CAr = res[iy1][ix2].CAr + s3; } else if (ix4 == ix1) { //implementation option 22 dy2 = frac(sy2); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s1 = dx3 / cosB + dy4 / sinB - 1; if (s1 > 0) { s1 = s1 * s1*triS; res[iy4][ix3].R = res[iy4][ix3].R + eR * s1; res[iy4][ix3].G = res[iy4][ix3].G + Ge * s1; res[iy4][ix3].B = res[iy4][ix3].B + Be * s1; res[iy4][ix3].CAr = res[iy4][ix3].CAr + s1; } else s1 = 0; s5 = dx3 / sinB + dy2 / cosB - 1; if (s5 > 0) { s5 = s5 * s5*triS; res[iy2][ix3].R = res[iy2][ix3].R + eR * s5; res[iy2][ix3].G = res[iy2][ix3].G + Ge * s5; res[iy2][ix3].B = res[iy2][ix3].B + Be * s5; res[iy2][ix3].CAr = res[iy2][ix3].CAr + s5; } else s5 = 0; s2 = dy4 * dy4 / sinBucosBd2 - s1; s6 = dy2 * dy2 / sinBucosBd2 - s5; s3 = dx3 * dx3 / sinBucosBd2; s4 = 1 - s3 - s2 - s6; s3 = s3 - s1 - s5; res[iy4][ix4].R = res[iy4][ix4].R + eR * s2; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s2; res[iy4][ix4].B = res[iy4][ix4].B + Be * s2; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s2; res[iy3][ix3].R = res[iy3][ix3].R + eR * s3; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s3; res[iy3][ix3].B = res[iy3][ix3].B + Be * s3; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s3; res[iy2][ix2].R = res[iy2][ix2].R + eR * s6; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s6; res[iy2][ix2].B = res[iy2][ix2].B + Be * s6; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s6; res[iy3][ix2].R = res[iy3][ix2].R + eR * s4; res[iy3][ix2].G = res[iy3][ix2].G + Ge * s4; res[iy3][ix2].B = res[iy3][ix2].B + Be * s4; res[iy3][ix2].CAr = res[iy3][ix2].CAr + s4; } else { //implementation option 23 dx1 = frac(sx1); dy2 = frac(sy2); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s1 = dx3 / cosB + dy4 / sinB - 1; if (s1 > 0) { s1 = s1 * s1*triS; res[iy4][ix3].R = res[iy4][ix3].R + eR * s1; res[iy4][ix3].G = res[iy4][ix3].G + Ge * s1; res[iy4][ix3].B = res[iy4][ix3].B + Be * s1; res[iy4][ix3].CAr = res[iy4][ix3].CAr + s1; } else s1 = 0; s3 = dx1 / sinB + dy4 / cosB - 1; if (s3 > 0) { s3 = s3 * s3*triS; res[iy4][ix1].R = res[iy4][ix1].R + eR * s3; res[iy4][ix1].G = res[iy4][ix1].G + Ge * s3; res[iy4][ix1].B = res[iy4][ix1].B + Be * s3; res[iy4][ix1].CAr = res[iy4][ix1].CAr + s3; } else s3 = 0; s7 = dx3 / sinB + dy2 / cosB - 1; if (s7 > 0) { s7 = s7 * s7*triS; res[iy2][ix3].R = res[iy2][ix3].R + eR * s7; res[iy2][ix3].G = res[iy2][ix3].G + Ge * s7; res[iy2][ix3].B = res[iy2][ix3].B + Be * s7; res[iy2][ix3].CAr = res[iy2][ix3].CAr + s7; } else s7 = 0; s9 = dx1 / cosB + dy2 / sinB - 1; if (s9 > 0) { s9 = s9 * s9*triS; res[iy2][ix1].R = res[iy2][ix1].R + eR * s9; res[iy2][ix1].G = res[iy2][ix1].G + Ge * s9; res[iy2][ix1].B = res[iy2][ix1].B + Be * s9; res[iy2][ix1].CAr = res[iy2][ix1].CAr + s9; } else s9 = 0; s2 = dy4 * dy4 / sinBucosBd2 - s1 - s3; s8 = dy2 * dy2 / sinBucosBd2 - s7 - s9; s4 = dx3 * dx3 / sinBucosBd2; s6 = dx1 * dx1 / sinBucosBd2; s5 = 1 - s4 - s6 - s2 - s8; s4 = s4 - s1 - s7; s6 = s6 - s3 - s9; res[iy3][ix3].R = res[iy3][ix3].R + eR * s4; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s4; res[iy3][ix3].B = res[iy3][ix3].B + Be * s4; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s4; res[iy4][ix4].R = res[iy4][ix4].R + eR * s2; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s2; res[iy4][ix4].B = res[iy4][ix4].B + Be * s2; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s2; res[iy1][ix1].R = res[iy1][ix1].R + eR * s6; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s6; res[iy1][ix1].B = res[iy1][ix1].B + Be * s6; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s6; res[iy2][ix2].R = res[iy2][ix2].R + eR * s8; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s8; res[iy2][ix2].B = res[iy2][ix2].B + Be * s8; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s8; res[iy3][ix4].R = res[iy3][ix4].R + eR * s5; res[iy3][ix4].G = res[iy3][ix4].G + Ge * s5; res[iy3][ix4].B = res[iy3][ix4].B + Be * s5; res[iy3][ix4].CAr = res[iy3][ix4].CAr + s5; } else if (ix3 == ix4) { //implementation option 20 dx1 = frac(sx1); dy2 = frac(sy2); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s2 = dx1 / sinB + dy4 / cosB - 1; if (s2 > 0) { s2 = s2 * s2*triS; res[iy4][ix1].R = res[iy4][ix1].R + eR * s2; res[iy4][ix1].G = res[iy4][ix1].G + Ge * s2; res[iy4][ix1].B = res[iy4][ix1].B + Be * s2; res[iy4][ix1].CAr = res[iy4][ix1].CAr + s2; } else s2 = 0; s5 = dx3 / sinB + dy2 / cosB - 1; if (s5 > 0) { s5 = s5 * s5*triS; res[iy2][ix3].R = res[iy2][ix3].R + eR * s5; res[iy2][ix3].G = res[iy2][ix3].G + Ge * s5; res[iy2][ix3].B = res[iy2][ix3].B + Be * s5; res[iy2][ix3].CAr = res[iy2][ix3].CAr + s5; } else s5 = 0; s6 = dy2 * dy2 / sinBucosBd2 - s5; s1 = dy4 * dy4 / sinBucosBd2 - s2; s3 = 0.5f + (dx3 - dx1) / cosAu2; s4 = 1.0f - s3 - s2 - s6; s3 = s3 - s1 - s5; res[iy4][ix4].R = res[iy4][ix4].R + eR * s1; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s1; res[iy4][ix4].B = res[iy4][ix4].B + Be * s1; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s1; res[iy3][ix3].R = res[iy3][ix3].R + eR * s3; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s3; res[iy3][ix3].B = res[iy3][ix3].B + Be * s3; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s3; res[iy1][ix1].R = res[iy1][ix1].R + eR * s4; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s4; res[iy1][ix1].B = res[iy1][ix1].B + Be * s4; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s4; res[iy2][ix2].R = res[iy2][ix2].R + eR * s6; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s6; res[iy2][ix2].B = res[iy2][ix2].B + Be * s6; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s6; } else { //implementation option 19 dx1 = frac(sx1); dy2 = frac(sy2); dx3 = 1 - frac(sx3); dy4 = 1 - frac(sy4); s1 = dx3 / cosB + dy4 / sinB - 1; if (s1 > 0) { s1 = s1 * s1*triS; res[iy4][ix3].R = res[iy4][ix3].R + eR * s1; res[iy4][ix3].G = res[iy4][ix3].G + Ge * s1; res[iy4][ix3].B = res[iy4][ix3].B + Be * s1; res[iy4][ix3].CAr = res[iy4][ix3].CAr + s1; } else s1 = 0; s6 = dx1 / cosB + dy2 / sinB - 1; if (s6 > 0) { s6 = s6 * s6*triS; res[iy2][ix1].R = res[iy2][ix1].R + eR * s6; res[iy2][ix1].G = res[iy2][ix1].G + Ge * s6; res[iy2][ix1].B = res[iy2][ix1].B + Be * s6; res[iy2][ix1].CAr = res[iy2][ix1].CAr + s6; } else s6 = 0; s2 = dy4 * dy4 / sinBucosBd2 - s1; s5 = dy2 * dy2 / sinBucosBd2 - s6; s3 = 0.5f + (dx3 - dx1) / cosBu2; s4 = 1 - s3 - s2 - s6; s3 = s3 - s1 - s5; res[iy4][ix4].R = res[iy4][ix4].R + eR * s2; res[iy4][ix4].G = res[iy4][ix4].G + Ge * s2; res[iy4][ix4].B = res[iy4][ix4].B + Be * s2; res[iy4][ix4].CAr = res[iy4][ix4].CAr + s2; res[iy3][ix3].R = res[iy3][ix3].R + eR * s3; res[iy3][ix3].G = res[iy3][ix3].G + Ge * s3; res[iy3][ix3].B = res[iy3][ix3].B + Be * s3; res[iy3][ix3].CAr = res[iy3][ix3].CAr + s3; res[iy1][ix1].R = res[iy1][ix1].R + eR * s4; res[iy1][ix1].G = res[iy1][ix1].G + Ge * s4; res[iy1][ix1].B = res[iy1][ix1].B + Be * s4; res[iy1][ix1].CAr = res[iy1][ix1].CAr + s4; res[iy2][ix2].R = res[iy2][ix2].R + eR * s5; res[iy2][ix2].G = res[iy2][ix2].G + Ge * s5; res[iy2][ix2].B = res[iy2][ix2].B + Be * s5; res[iy2][ix2].CAr = res[iy2][ix2].CAr + s5; } } row[g_Width].X = x2; row[g_Width].Y = y2; } unsigned char* data = data3; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { A = 1 - res[j][i].CAr; unsigned char r = Doedin(res[j][i].R + FonR * A); unsigned char g = Doedin(res[j][i].G + FonG * A); unsigned char b = Doedin(res[j][i].B + FonB * A); *(data + 0) = r; *(data + 1) = g; *(data + 2) = b; data += component; } } };