LogoMarkerSymbol.cpp
// Copyright 2012 ESRI // // All rights reserved under the copyright laws of the United States // and applicable international laws, treaties, and conventions. // // You may freely redistribute and use this sample code, with or // without modification, provided you include the original copyright // notice and use restrictions. // // See the use restrictions. // // LogoMarkerSymbol.cpp : Implementation of CLogoMarkerSymbol #include "stdafx.h" #include "LogoMarkerSymbolVC.h" #include "LogoMarkerSymbol.h" #include <math.h> ///////////////////////////////////////////////////////////////////////////// // Helper Functions - Generic double Radians(double dDegrees) { double dPi = 4 * atan(1.0); return dDegrees * dPi / 180; } long round(float a) { return (long)floor(a + 0.5f); } long round(double a) { return (long)floor(a + 0.5f); } bool qaDoubleCompare(double TestValue, double ExpectedValue, int precision = 8) { double v1,v2,vx,tx; tx = pow(10.0, precision); v1 = (int) (fabs(TestValue) * tx) / tx; v2 = (int)(fabs(ExpectedValue) * tx) / tx; vx = (v1 - v2) * tx; return (abs((int)vx) + 1) <= 2 ; } void CreatePoint(IPointPtr* ippPoint, double XVal, double YVal, double ZVal = 0, double MVal = 0, long IDVal = 0) { ippPoint->CreateInstance(CLSID_Point); (*ippPoint)->PutCoords(XVal, YVal); (*ippPoint)->put_M(MVal); (*ippPoint)->put_Z(ZVal); (*ippPoint)->put_ID(IDVal); return; } void CreateCArcCenterFromTo(ICircularArcPtr* ippCArc, IPointPtr ipCPt, IPointPtr ipFPt, IPointPtr ipTPt) { ippCArc->CreateInstance(CLSID_CircularArc); (*ippCArc)->PutCoords(ipCPt, ipFPt, ipTPt, esriArcClockwise); return; } void ToMapPoint(IDisplayTransformationPtr ipDTrans, double dX, double dY, IPoint** ippPoint) { if (ipDTrans == NULL) { ::CoCreateInstance(CLSID_Point, NULL, 0, IID_IPoint, (void**)ippPoint); (*ippPoint)->PutCoords(dX, dY); } else ipDTrans->ToMapPoint(round(dX), round(dY), ippPoint); } void FromMapPoint(IDisplayTransformationPtr ipDTrans, IPointPtr ipPoint, double* pdX, double* pdY) { if (ipDTrans == NULL) ipPoint->QueryCoords(pdX, pdY); else { long lX, lY; ipDTrans->FromMapPoint(ipPoint, &lX, &lY); *pdX = lX; *pdY = lY; } } ///////////////////////////////////////////////////////////////////////////// // CLogoMarkerSymbol ///////////////////////////////////////////////////////////////////////////// CLogoMarkerSymbol::CLogoMarkerSymbol() : m_dPi(3.141592653), m_lhDC(0), m_lPen(0), m_lOldPen(0), m_lBrushTop(0), m_lBrushLeft(0), m_lBrushRight(0), m_lOldBrush(0), /*m_lROP2Old;*/ m_dDeviceRatio(0.0), m_dDeviceXOffset(0.0), m_dDeviceYOffset(0.0), /*m_Coords[6]*/ m_dDeviceRadius(0.0), m_ipTopColor(CLSID_RgbColor), m_ipLeftColor(CLSID_RgbColor), m_ipRightColor(CLSID_RgbColor), m_ipBorderColor(CLSID_RgbColor), m_lROP2(esriROPCopyPen), m_dSize(40.0), m_dXOffset(0.0), m_dYOffset(0.0), m_dAngle(0.0), m_bsDisplayName(L"Logo Marker Symbol (C++)"), m_bRotWithTrans(VARIANT_TRUE), m_dMapRotation(0.0), m_lMapLevel(0) { m_ipTopColor->put_RGB(RGB(255,0,0)); m_ipLeftColor->put_RGB(RGB(170,0,0)); m_ipRightColor->put_RGB(RGB(128,0,0)); m_ipBorderColor->put_RGB(RGB(0,0,0)); } CLogoMarkerSymbol::~CLogoMarkerSymbol() { //m_lhDC = 0; } // Helper Functions - Class double CLogoMarkerSymbol::MapToPoints(ITransformationPtr ipTrans, double dMapSize) { if (ipTrans == NULL) { return dMapSize / m_dDeviceRatio; } else { IDisplayTransformationPtr ipDTrans(ipTrans); double dResult; ipDTrans->ToPoints(dMapSize, &dResult); return dResult; } } double CLogoMarkerSymbol::PointsToMap(ITransformationPtr ipTrans, double dPointSizeSize) { if (ipTrans == NULL) return dPointSizeSize * m_dDeviceRatio; else { IDisplayTransformationPtr ipDTrans(ipTrans); double dResult; ipDTrans->FromPoints(dPointSizeSize, &dResult); return dResult; } } void CLogoMarkerSymbol::SetupDeviceRatio(HDC hdc, IDisplayTransformationPtr ipDTrans) { if (ipDTrans == NULL) { if (hdc) m_dDeviceRatio = ::GetDeviceCaps(hdc, LOGPIXELSX) / 72; else m_dDeviceRatio = ::GetDeviceCaps(::GetDC(NULL), LOGPIXELSX) / 72; //use DC of the screen } else { double dDpi; ipDTrans->get_Resolution(&dDpi); if (dDpi) { m_dDeviceRatio = dDpi / 72; double dScale; ipDTrans->get_ReferenceScale(&dScale); if (dScale) { double dScaleRatio; ipDTrans->get_ScaleRatio(&dScaleRatio); m_dDeviceRatio = m_dDeviceRatio * dScale / dScaleRatio; } } } } void CLogoMarkerSymbol::RotateCoords() { //Correct for anticlockwise rotation double dAngle; dAngle = 360 - m_dAngle + m_dMapRotation; if (qaDoubleCompare(dAngle, 360.0)) return; double dRadians = Radians(dAngle); IAffineTransformation2DPtr ipA2D(CLSID_AffineTransformation2D); ipA2D->Move(-m_ptCoords[1].x, -m_ptCoords[1].y); ipA2D->Rotate(dRadians); ipA2D->Move(m_ptCoords[1].x, m_ptCoords[1].y); ITransform2DPtr ipT2D; double dX, dY, dCenX, dCenY, dCosRad, dSinRad; dCenX = m_ptCoords[1].x; dCenY = m_ptCoords[1].y; dCosRad = cos(dRadians); dSinRad = sin(dRadians); for (int i = 0; i < 4; ++i) { if (i != 1) { /* dX = m_ptCoords[i].x; dY = m_ptCoords[i].y; dX = dCenX + ((dX - dCenX) * dCosRad) - ((dY - dCenY) * dSinRad); dY = dCenY + ((dX - dCenX) * dSinRad) + ((dY - dCenY) * dCosRad); /**/ IPointPtr ipPt(CLSID_Point); ipPt->PutCoords((double)m_ptCoords[i].x, (double)m_ptCoords[i].y); ipT2D = ipPt; ipT2D->Transform(esriTransformForward, ipA2D); ipPt->get_X(&dX); ipPt->get_Y(&dY); /**/ m_ptCoords[i].x = round(dX); m_ptCoords[i].y = round(dY); } } } void CLogoMarkerSymbol::CalcCoords(double dX, double dY) { //This function calculates the required coordinates for each symbol //based on the feature's geometry. These coordinates are in Device units double dVal; dVal = sqrt(pow(m_dDeviceRadius, 2) / 2.0); //We account for the offset in the calculation of the center point. All other //points are then calculated from this. Y coordinates are top to bottom in Y axis. m_ptCoords[1].x = round(dX + m_dDeviceXOffset); m_ptCoords[1].y = round(dY - m_dDeviceYOffset); m_ptCoords[0].x = round(m_ptCoords[1].x - dVal); m_ptCoords[0].y = round(m_ptCoords[1].y - dVal); m_ptCoords[3].x = round(m_ptCoords[1].x + dVal); m_ptCoords[3].y = round(m_ptCoords[1].y + dVal); m_ptCoords[2].x = m_ptCoords[0].x; m_ptCoords[2].y = m_ptCoords[3].y; m_ptCoords[4].x = round(m_ptCoords[1].x - m_dDeviceRadius); m_ptCoords[4].y = round(m_ptCoords[1].y - m_dDeviceRadius); m_ptCoords[5].x = round(m_ptCoords[1].x + m_dDeviceRadius); m_ptCoords[5].y = round(m_ptCoords[1].y + m_dDeviceRadius); RotateCoords(); } void CLogoMarkerSymbol::QueryBoundsFromGeom(OLE_HANDLE hdc, IDisplayTransformationPtr ipTransform, IPolygonPtr ipBoundary, IPointPtr ipPoint) { //Calculate Size, XOffset and YOffset of the shape in Map units. double dMapSize, dMapXOffset, dMapYOffset; dMapSize = PointsToMap(ipTransform, m_dSize); if (qaDoubleCompare(m_dXOffset, 0.0)) dMapXOffset = PointsToMap(ipTransform, m_dXOffset); if (qaDoubleCompare(m_dYOffset, 0.0)) dMapYOffset = PointsToMap(ipTransform, m_dYOffset); double dX, dY; ipPoint->get_X(&dX); ipPoint->get_Y(&dY); ipPoint->PutCoords(dX + dMapXOffset, dY + dMapYOffset); //Set up the device ratio. SetupDeviceRatio((HDC)hdc, (IDisplayTransformationPtr)ipTransform); IPointCollectionPtr ipPtColl(ipBoundary); ISegmentCollectionPtr ipSegColl(ipBoundary); double dVal, dRad; //dVal is the measurement of the short side of a Triangles are based on. dRad = dMapSize / 2.0; dVal = sqrt((dRad * dRad / 2.0)); ipPoint->get_X(&dX); ipPoint->get_Y(&dY); IPointPtr ipPt; CreatePoint((IPointPtr*)&ipPt, dX + dVal, dY - dVal); ipPtColl->AddPoint(ipPt); CreatePoint((IPointPtr*)&ipPt, dX - dVal, dY - dVal); ipPtColl->AddPoint(ipPt); CreatePoint((IPointPtr*)&ipPt, dX - dVal, dY + dVal); ipPtColl->AddPoint(ipPt); ICircularArcPtr ipCArc; IPointPtr ipFPt, ipTPt; ipPtColl->get_Point(2, &ipFPt); ipPtColl->get_Point(0, &ipTPt); CreateCArcCenterFromTo((ICircularArcPtr*)&ipCArc, ipPoint, ipFPt, ipTPt); ipSegColl->AddSegment((ISegmentSamplePtr)ipCArc); //Account for rotation also. if (qaDoubleCompare(m_dAngle, 0.0)) { ITransform2DPtr ipTrans2D(ipBoundary); ipTrans2D->Rotate(ipPoint, Radians(m_dAngle)); } } ///////////////////////////////////////////////////////////////////////////// // IClone STDMETHODIMP CLogoMarkerSymbol::Clone(IClone **Clone) { if (Clone == NULL) return E_POINTER; ::CoCreateInstance(CLSID_LogoMarkerSymbol, NULL,CLSCTX_INPROC_SERVER ,IID_IClone, (void**) Clone); IClonePtr ipSrc; this->QueryInterface(IID_IClone, (void**)&ipSrc); HRESULT hr = (*Clone)->Assign(ipSrc); return hr; } STDMETHODIMP CLogoMarkerSymbol::Assign(IClone *src) { HRESULT hr; //ILogoMarkerSymbol ILogoMarkerSymbolPtr ipLogo; if (FAILED(hr = src->QueryInterface(IID_ILogoMarkerSymbol, (void**)&ipLogo))) return hr; ipLogo->get_ColorBorder(&m_ipBorderColor); ipLogo->get_ColorLeft(&m_ipLeftColor); ipLogo->get_ColorRight(&m_ipRightColor); ipLogo->get_ColorTop(&m_ipTopColor); //IMarkerSymbol IMarkerSymbolPtr ipMarkerSym; if (FAILED(hr = src->QueryInterface(IID_IMarkerSymbol, (void**)&ipMarkerSym))) return hr; ipMarkerSym->get_Angle(&m_dAngle); ipMarkerSym->get_Size(&m_dSize); ipMarkerSym->get_XOffset(&m_dXOffset); ipMarkerSym->get_YOffset(&m_dYOffset); //ISymbol ISymbolPtr ipSymbol; if (FAILED(hr = src->QueryInterface(IID_ISymbol, (void**)&ipSymbol))) return hr; ipSymbol->get_ROP2(&m_lROP2); //ISymbolRotation ISymbolRotationPtr ipSymbolRot; if (FAILED(hr = src->QueryInterface(IID_ISymbolRotation, (void**)&ipSymbolRot))) return hr; ipSymbolRot->get_RotateWithTransform(&m_bRotWithTrans); //IMapLevel IMapLevelPtr ipMapLevel; if (FAILED(hr = src->QueryInterface(IID_IMapLevel, (void**)&ipMapLevel))) return hr; ipMapLevel->get_MapLevel(&m_lMapLevel); //IDisplayName - does not have any writable properties //IMarkerMask does not have any properties return S_OK; } STDMETHODIMP CLogoMarkerSymbol::IsEqual(IClone *other, VARIANT_BOOL *equal) { if (equal == NULL) return E_POINTER; HRESULT hr; //ILogoMarkerSymbol ILogoMarkerSymbolPtr ipLogo; if (FAILED(hr = other->QueryInterface(IID_ILogoMarkerSymbol, (void**)&ipLogo))) return hr; OLE_COLOR lRGB, lOtherRGB; IColorPtr ipColor; //border ipLogo->get_ColorBorder(&ipColor); ipColor->get_RGB(&lOtherRGB); m_ipBorderColor->get_RGB(&lRGB); lRGB == lOtherRGB ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //left ipLogo->get_ColorLeft(&ipColor); ipColor->get_RGB(&lOtherRGB); m_ipLeftColor->get_RGB(&lRGB); lRGB == lOtherRGB ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //right ipLogo->get_ColorRight(&ipColor); ipColor->get_RGB(&lOtherRGB); m_ipRightColor->get_RGB(&lRGB); lRGB == lOtherRGB ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //top ipLogo->get_ColorTop(&ipColor); ipColor->get_RGB(&lOtherRGB); m_ipTopColor->get_RGB(&lRGB); lRGB == lOtherRGB ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //IMarkerSymbol IMarkerSymbolPtr ipMarkerSym; if (FAILED(hr = other->QueryInterface(IID_IMarkerSymbol, (void**)&ipMarkerSym))) return hr; double dOther; //angle ipMarkerSym->get_Angle(&dOther); qaDoubleCompare(m_dAngle, dOther) ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //size ipMarkerSym->get_Size(&dOther); qaDoubleCompare(m_dSize, dOther) ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //xoffset ipMarkerSym->get_XOffset(&dOther); qaDoubleCompare(m_dXOffset, dOther) ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //yoffset ipMarkerSym->get_YOffset(&dOther); qaDoubleCompare(m_dYOffset, dOther) ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //ISymbol ISymbolPtr ipSymbol; esriRasterOpCode lROPOther; if (FAILED(hr = other->QueryInterface(IID_ISymbol, (void**)&ipSymbol))) return hr; ipSymbol->get_ROP2(&lROPOther); m_lROP2 == lROPOther ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //ISymbolRotation ISymbolRotationPtr ipSymbolRot; VARIANT_BOOL bOther; if (FAILED(hr = other->QueryInterface(IID_ISymbolRotation, (void**)&ipSymbolRot))) return hr; ipSymbolRot->get_RotateWithTransform(&bOther); m_bRotWithTrans == bOther ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //IMapLevel IMapLevelPtr ipMapLevel; long lOther; if (FAILED(hr = other->QueryInterface(IID_IMapLevel, (void**)&ipMapLevel))) return hr; ipMapLevel->get_MapLevel(&lOther); m_lMapLevel == lOther ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //IDisplayName IDisplayNamePtr ipDisplayName; CComBSTR bsOther; if (FAILED(hr = other->QueryInterface(IID_IDisplayName, (void**)&ipDisplayName))) return hr; ipDisplayName->get_NameString(&bsOther); m_bsDisplayName == bsOther ? *equal = VARIANT_TRUE : VARIANT_FALSE; if (*equal == VARIANT_FALSE) return S_OK; //IMarkerMask does not have any properties return S_OK; } STDMETHODIMP CLogoMarkerSymbol::IsIdentical(IClone *other, VARIANT_BOOL *identical) { if (identical == NULL) return E_POINTER; *identical = VARIANT_FALSE; if (other == NULL) return S_OK; IUnknownPtr ipUnk, ipUnkOther; HRESULT hr; if (FAILED(hr = other->QueryInterface(IID_IUnknown, (void**)&ipUnkOther))) return hr; if (FAILED(hr = this->QueryInterface(IID_IUnknown, (void**)&ipUnk))) return hr; if (ipUnk == ipUnkOther) *identical = VARIANT_TRUE; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IDisplayName STDMETHODIMP CLogoMarkerSymbol::get_NameString(BSTR *DisplayName) { if (DisplayName == NULL) return E_POINTER; *DisplayName = ::SysAllocString(m_bsDisplayName); return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IMarkerSymbol STDMETHODIMP CLogoMarkerSymbol::get_Size(double *Size) { if (! Size) return E_POINTER; *Size = m_dSize; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::put_Size(double Size) { m_dSize = Size; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::get_Color(IColor **Color) { if (! Color) return E_POINTER; IClonePtr ipClone(m_ipTopColor), ipCloned; ipClone->Clone(&ipCloned); return ipCloned.QueryInterface(IID_IColor, (void**)Color); } STDMETHODIMP CLogoMarkerSymbol::put_Color(IColor *Color) { IClonePtr ipClone(Color), ipCloned; HRESULT hr = ipClone->Clone(&ipCloned); m_ipTopColor = ipCloned; return hr; } STDMETHODIMP CLogoMarkerSymbol::get_Angle(double *Angle) { if (!Angle) return E_POINTER; *Angle = m_dAngle; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::put_Angle(double Angle) { if (Angle > 360) m_dAngle = Angle - (((int)(Angle / 360)) * 360); else m_dAngle = Angle; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::get_XOffset(double *XOffset) { if (!XOffset) return E_POINTER; *XOffset = m_dXOffset; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::put_XOffset(double XOffset) { m_dXOffset = XOffset; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::get_YOffset(double *YOffset) { if (! YOffset) return E_POINTER; *YOffset = m_dYOffset; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::put_YOffset(double YOffset) { m_dYOffset = YOffset; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IPersistVariant STDMETHODIMP CLogoMarkerSymbol::get_ID(IUID **objectID) { if (! objectID) return E_POINTER; LPOLESTR lpTmp; StringFromCLSID(CLSID_LogoMarkerSymbol, &lpTmp); CComBSTR bstTmp(lpTmp); CComVariant vVariant(bstTmp); IUIDPtr ipUID(CLSID_UID); HRESULT hr = ipUID->put_Value(vVariant); if (FAILED(hr)) return hr; *objectID = ipUID; if (*objectID != 0) (*objectID)->AddRef(); return S_OK; } STDMETHODIMP CLogoMarkerSymbol::Load(IVariantStream *Stream) { CComVariant vLoad; HRESULT hr; //load ISymbol properties if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_I4) m_lROP2 = (esriRasterOpCode)vLoad.lVal; else return E_FAIL; vLoad.Clear(); //load IMarkerSymbol properties if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_R8) m_dSize = vLoad.dblVal; else return E_FAIL; vLoad.Clear(); if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_R8) m_dXOffset = vLoad.dblVal; else return E_FAIL; vLoad.Clear(); if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_R8) m_dYOffset = vLoad.dblVal; else return E_FAIL; vLoad.Clear(); if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_R8) m_dAngle = vLoad.dblVal; else return E_FAIL; vLoad.Clear(); //load ISymbolRotation properties if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_BOOL) m_bRotWithTrans = vLoad.boolVal; else return E_FAIL; vLoad.Clear(); //load IMapLevel properties if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_I4) m_lMapLevel = vLoad.lVal; else return E_FAIL; vLoad.Clear(); //load custom properties if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_UNKNOWN) m_ipTopColor = (IColorPtr) vLoad.punkVal; else return E_FAIL; vLoad.Clear(); if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_UNKNOWN) m_ipLeftColor = (IColorPtr) vLoad.punkVal; else return E_FAIL; vLoad.Clear(); if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_UNKNOWN) m_ipRightColor = (IColorPtr) vLoad.punkVal; else return E_FAIL; vLoad.Clear(); if (FAILED(hr = Stream->Read(&vLoad))) return hr; if (vLoad.vt == VT_UNKNOWN) m_ipBorderColor = (IColorPtr) vLoad.punkVal; else return E_FAIL; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::Save(IVariantStream *Stream) { CComVariant vSave; HRESULT hr; //persist ISymbol properties vSave = (long)m_lROP2; if (FAILED(hr = Stream->Write(vSave))) return hr; //persist IMarkerSymbol properties vSave = m_dSize; if (FAILED(hr = Stream->Write(vSave))) return hr; vSave = m_dXOffset; if (FAILED(hr = Stream->Write(vSave))) return hr; vSave = m_dYOffset; if (FAILED(hr = Stream->Write(vSave))) return hr; vSave = m_dAngle; if (FAILED(hr = Stream->Write(vSave))) return hr; //persist ISymbolRotation properties // CComVariant does not have assignment operator // for VARIANT_BOOL, so do this as for the raw datatype vSave.Clear(); vSave.vt = VT_BOOL; vSave.boolVal = m_bRotWithTrans; if (FAILED(hr = Stream->Write(vSave))) return hr; //persist IMapLevel properties vSave = m_lMapLevel; if (FAILED(hr = Stream->Write(vSave))) return hr; //persist custom properties vSave = (IUnknown*)m_ipTopColor; if (FAILED(hr = Stream->Write(vSave))) return hr; vSave = (IUnknown*)m_ipLeftColor; if (FAILED(hr = Stream->Write(vSave))) return hr; vSave = (IUnknown*)m_ipRightColor; if (FAILED(hr = Stream->Write(vSave))) return hr; vSave = (IUnknown*)m_ipBorderColor; if (FAILED(hr = Stream->Write(vSave))) return hr; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // ISymbol STDMETHODIMP CLogoMarkerSymbol::SetupDC(OLE_HANDLE hDC, ITransformation *Transformation) { //Store the DisplayTransformation and display handle for use by Draw and ResetDC. m_ipTrans = Transformation; m_lhDC = (HDC)hDC; //Set up the device ratio for use by Draw and the rest of SetupDC. IDisplayTransformationPtr ipDTrans(Transformation); SetupDeviceRatio(m_lhDC, m_ipTrans); //Calculate the new Radius for the symbol from the Size (width) overall. m_dDeviceRadius = (m_dSize / 2) * m_dDeviceRatio; m_dDeviceXOffset = m_dXOffset * m_dDeviceRatio; m_dDeviceYOffset = m_dYOffset * m_dDeviceRatio; //Check if we need to rotate the symbol based on the ISymbolRotation interface. if (m_bRotWithTrans == VARIANT_TRUE) m_ipTrans->get_Rotation(&m_dMapRotation); else m_dMapRotation = 0; //Setup the Pen which is used to outline the shapes. OLE_COLOR lRGB; m_ipBorderColor->get_RGB(&lRGB); m_lPen = ::CreatePen(PS_SOLID, (int)m_dDeviceRatio, lRGB); // * m_dDeviceRatio allows the pen size to scale //Set the appropriate raster operation code for this draw, according to the //ISymbol interface. m_lROP2Old = (esriRasterOpCode)::SetROP2(m_lhDC, (int)m_lROP2); //Set up three solid brushes to fill in the shapes with the different color fills. m_ipTopColor->get_RGB(&lRGB); m_lBrushTop = CreateSolidBrush(lRGB); m_ipLeftColor->get_RGB(&lRGB); m_lBrushLeft = CreateSolidBrush(lRGB); m_ipRightColor->get_RGB(&lRGB); m_lBrushRight = CreateSolidBrush(lRGB); //Select in the new pen and store the old pen - essential for use during cleanup. m_lOldPen = (HPEN)::SelectObject(m_lhDC, m_lPen); return S_OK; } STDMETHODIMP CLogoMarkerSymbol::ResetDC() { //Select back the old GDI pen and ROP code, and release other GDI resources m_lROP2 = (esriRasterOpCode)::SetROP2(m_lhDC, (int)m_lROP2Old); SelectObject(m_lhDC, m_lOldPen); DeleteObject(m_lPen); SelectObject(m_lhDC, m_lOldBrush); DeleteObject (m_lBrushTop); DeleteObject (m_lBrushLeft); DeleteObject (m_lBrushRight); m_ipTrans = 0; m_lhDC = 0; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::Draw(IGeometry *Geometry) { if (!Geometry) return E_POINTER; if (!m_lhDC) return E_FAIL; if (m_ipTopColor == NULL || m_ipLeftColor == NULL || m_ipRightColor == NULL || m_ipBorderColor == NULL) return E_FAIL; IPointPtr ipPt(Geometry); if (ipPt == NULL) return E_FAIL; VARIANT_BOOL dummy; if (Geometry->get_IsEmpty(&dummy) == S_OK) return S_OK; //Transform the Point coords to device coords, accounting for rotation, offset etc. double dCenterX, dCenterY; FromMapPoint((IDisplayTransformation*)m_ipTrans, ipPt, &dCenterX, &dCenterY); CalcCoords(dCenterX, dCenterY); //Draw the chord, and two polygons, and flood fill them. m_lOldBrush = (HBRUSH)::SelectObject(m_lhDC, m_lBrushTop); ::Chord(m_lhDC, m_ptCoords[4].x, m_ptCoords[4].y, m_ptCoords[5].x, m_ptCoords[5].y, m_ptCoords[3].x, m_ptCoords[3].y, m_ptCoords[0].x, m_ptCoords[0].y); ::SelectObject(m_lhDC, m_lBrushLeft); ::Polygon(m_lhDC, &m_ptCoords[0], 3); ::SelectObject(m_lhDC, m_lBrushRight); ::Polygon(m_lhDC, &m_ptCoords[1], 3); ::SelectObject(m_lhDC, m_lOldBrush); return S_OK; } STDMETHODIMP CLogoMarkerSymbol::QueryBoundary(OLE_HANDLE hDC, ITransformation *displayTransform, IGeometry *Geometry, IPolygon *Boundary) { //Check input parameters. Boundary may be a preexisting Polygon, so //make sure it's geometry is cleared. if (Geometry == NULL || Boundary == NULL) return E_POINTER; IPointPtr ipPt(Geometry); if (ipPt == NULL) return E_FAIL; Boundary->SetEmpty(); IDisplayTransformationPtr ipDTrans(displayTransform); QueryBoundsFromGeom(hDC, ipDTrans, Boundary, ipPt); return S_OK; } STDMETHODIMP CLogoMarkerSymbol::get_ROP2(esriRasterOpCode *DrawMode) { if (!DrawMode) return E_POINTER; *DrawMode = m_lROP2; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::put_ROP2(esriRasterOpCode DrawMode) { if (DrawMode < 1) m_lROP2 = esriROPCopyPen; else m_lROP2 = DrawMode; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IMapLevel STDMETHODIMP CLogoMarkerSymbol::get_MapLevel(long *MapLevel) { if (!MapLevel) return E_POINTER; *MapLevel = m_lMapLevel; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::put_MapLevel(long MapLevel) { m_lMapLevel = MapLevel; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IMarkerMask STDMETHODIMP CLogoMarkerSymbol::QueryMarkerMask(OLE_HANDLE hDC, ITransformation *Transform, IGeometry *Geometry, IPolygon *Boundary) { //Code QueryBoundary using same steps as Draw. But add a step where //Points are converted to Map units, and then build an appropriate Polygon. if (Geometry == NULL || Boundary == NULL) return E_FAIL; IDisplayTransformationPtr ipDTrans(Transform); if (ipDTrans == NULL) return E_FAIL; IPointPtr ipPoint(Geometry); if (ipPoint == NULL) return E_FAIL; Boundary->SetEmpty(); QueryBoundsFromGeom(hDC, ipDTrans, Boundary, ipPoint); //Unlike ISymbol_QueryBoundary, QueryMarkerMask requires a Simple geometry. ITopologicalOperatorPtr ipTopo(Boundary); VARIANT_BOOL bSimple; ipTopo->get_IsKnownSimple(&bSimple); if (bSimple == VARIANT_FALSE) { ipTopo->get_IsSimple(&bSimple); if (bSimple == VARIANT_FALSE) { ipTopo->Simplify(); } } return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IPropertySupport STDMETHODIMP CLogoMarkerSymbol::Applies(LPUNKNOWN pUnk, VARIANT_BOOL *Applies) { if (!Applies) return E_POINTER; *Applies = VARIANT_FALSE; IColorPtr ipColor(pUnk); ILogoMarkerSymbolPtr ipLogo(pUnk); if (ipColor != NULL && ipLogo != NULL) *Applies = VARIANT_TRUE; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::CanApply(LPUNKNOWN pUnk, VARIANT_BOOL *CanApply) { return Applies(pUnk, CanApply); } STDMETHODIMP CLogoMarkerSymbol::get_Current(LPUNKNOWN pUnk, LPUNKNOWN *currentObject) { IColorPtr ipColor(pUnk); if (ipColor) { IColorPtr ipCurrentColor; get_Color(&ipCurrentColor); ipCurrentColor.QueryInterface(IID_IUnknown, (void**)currentObject); return S_OK; } ILogoMarkerSymbolPtr ipSymbol(pUnk); if (ipSymbol) { IClonePtr ipClone; Clone(&ipClone); ipClone.QueryInterface(IID_IUnknown, (void**)currentObject); return S_OK; } return E_FAIL; } STDMETHODIMP CLogoMarkerSymbol::Apply(LPUNKNOWN NewObject, LPUNKNOWN *oldObject) { IColorPtr ipColor(NewObject); if (ipColor) { get_Current(NewObject, oldObject); put_Color(ipColor); return S_OK; } ILogoMarkerSymbolPtr ipSymbol(NewObject); if (ipSymbol) { get_Current(NewObject, oldObject); IClonePtr ipClone(NewObject); Assign(ipClone); return S_OK; } return E_FAIL; } ///////////////////////////////////////////////////////////////////////////// // ISymbolRotation STDMETHODIMP CLogoMarkerSymbol::get_RotateWithTransform(VARIANT_BOOL *Flag) { if (! Flag) return E_POINTER; *Flag = m_bRotWithTrans; return S_OK; } STDMETHODIMP CLogoMarkerSymbol::put_RotateWithTransform(VARIANT_BOOL Flag) { m_bRotWithTrans = Flag; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // ILogoMarkerSymbol STDMETHODIMP CLogoMarkerSymbol::get_ColorBorder(IColor **ppColor) { IClonePtr ipSrc(m_ipBorderColor), ipClone; HRESULT hr = ipSrc->Clone(&ipClone); return ipClone.QueryInterface(IID_IColor, (void**)ppColor); } STDMETHODIMP CLogoMarkerSymbol::put_ColorBorder(IColor *pColor) { IClonePtr ipClone(pColor), ipCloned; HRESULT hr = ipClone->Clone(&ipCloned); m_ipBorderColor = ipCloned; return hr; } STDMETHODIMP CLogoMarkerSymbol::get_ColorLeft(IColor **ppColor) { IClonePtr ipClone(m_ipLeftColor), ipCloned; ipClone->Clone(&ipCloned); return ipCloned.QueryInterface(IID_IColor, (void**)ppColor); } STDMETHODIMP CLogoMarkerSymbol::put_ColorLeft(IColor *pColor) { IClonePtr ipClone(pColor), ipCloned; HRESULT hr = ipClone->Clone(&ipCloned); m_ipLeftColor = ipCloned; return hr; } STDMETHODIMP CLogoMarkerSymbol::get_ColorRight(IColor **ppColor) { IClonePtr ipClone(m_ipRightColor), ipCloned; ipClone->Clone(&ipCloned); return ipCloned.QueryInterface(IID_IColor, (void**)ppColor); } STDMETHODIMP CLogoMarkerSymbol::put_ColorRight(IColor *pColor) { IClonePtr ipClone(pColor), ipCloned; HRESULT hr = ipClone->Clone(&ipCloned); m_ipRightColor = ipCloned; return hr; } STDMETHODIMP CLogoMarkerSymbol::get_ColorTop(IColor **ppColor) { IClonePtr ipClone(m_ipTopColor), ipCloned; ipClone->Clone(&ipCloned); return ipCloned.QueryInterface(IID_IColor, (void**)ppColor); } STDMETHODIMP CLogoMarkerSymbol::put_ColorTop(IColor *pColor) { IClonePtr ipClone(pColor), ipCloned; HRESULT hr = ipClone->Clone(&ipCloned); m_ipTopColor = ipCloned; return hr; }