diff --git a/docs/AxInterop.MapWinGIS/AxMap.cs b/docs/AxInterop.MapWinGIS/AxMap.cs index 576e821c..e2a8c1c2 100644 --- a/docs/AxInterop.MapWinGIS/AxMap.cs +++ b/docs/AxInterop.MapWinGIS/AxMap.cs @@ -2319,6 +2319,18 @@ public virtual bool SetGeographicExtents(Extents pVal) /// \new491 Added in version 4.9.1 public float Longitude { get; set; } + /// + /// Sets the Latitude and Longitude of the center of the screen in one operation + /// + /// Requested Latitude in decimal degrees + /// Requested Longitude in decimal degrees + /// Map projection must be set in order for this method to work. + /// \new510 Added in version 5.1.0 + public void SetLatitudeLongitude(double latitude, double longitude) + { + throw new NotImplementedException(); + } + /// /// Gets or sets the current zoom level for the map. It corresponds to the zoom level of current tile provider. /// diff --git a/docs/Examples/src/CalculateArea.cs b/docs/Examples/src/CalculateArea.cs index cf3c316d..62178b2a 100644 --- a/docs/Examples/src/CalculateArea.cs +++ b/docs/Examples/src/CalculateArea.cs @@ -67,7 +67,7 @@ public void CalculateArea(AxMap axMap1, string dataPath) } //adding the new field in the end of the table - fldIndex = sf.EditAddField("CalcArea", FieldType.DOUBLE_FIELD, 12, 12); + fldIndex = sf.EditAddField("CalcArea", FieldType.DOUBLE_FIELD, 9, 12); if (fldIndex == -1) { MessageBox.Show("Failed to insert field: " + sf.ErrorMsg[sf.LastErrorCode]); diff --git a/docs/Interop.MapWinGIS/Com Classes/Identifier.cs b/docs/Interop.MapWinGIS/Com Classes/Identifier.cs index ffd8845f..d86d5c6a 100644 --- a/docs/Interop.MapWinGIS/Com Classes/Identifier.cs +++ b/docs/Interop.MapWinGIS/Com Classes/Identifier.cs @@ -34,10 +34,11 @@ public class Identifier /// public uint OutlineColor { get; set; } - /// - /// Gets or sets the handle of active layer, which is used when Identifer.IdentifierMode set to imSingleLayer. - /// - public int ActiveLayer { get; set; } + ///// + ///// Gets or sets the handle of active layer, which is used when Identifer.IdentifierMode set to imSingleLayer. + ///// NOTE: this method has been hidden, and functionality replaced through use of the ChooseLayer event. + ///// + //public int ActiveLayer { get; set; } } #if nsp } diff --git a/docs/Interop.MapWinGIS/Enumerations/Enumerations.cs b/docs/Interop.MapWinGIS/Enumerations/Enumerations.cs index d0b95f35..efbbc11c 100644 --- a/docs/Interop.MapWinGIS/Enumerations/Enumerations.cs +++ b/docs/Interop.MapWinGIS/Enumerations/Enumerations.cs @@ -2368,9 +2368,14 @@ public enum tkIdentifierMode /// imAllLayers = 0, /// - /// Only shapefile defined by Identifier.ActiveLayer will be identified. + /// Only shapefile specified in the context of AxMap.ChooseLayer event will be analyzed. /// imSingleLayer = 1, + /// + /// All shapefile layers with Shapefile.Identifiable property set to true will be analyzed, + /// but search will stop following the first (topmost) layer for which shapes are found. + /// + imAllLayersStopOnFirst = 2, } /// diff --git a/src/COM classes/Charts.cpp b/src/COM classes/Charts.cpp index 400dcab7..6db79b8e 100644 --- a/src/COM classes/Charts.cpp +++ b/src/COM classes/Charts.cpp @@ -1,13 +1,13 @@ /************************************************************************************** * File name: Charts.cpp * - * Project: MapWindow Open Source (MapWinGis ActiveX control) + * Project: MapWindow Open Source (MapWinGis ActiveX control) * Description: Implementation of CCharts * ************************************************************************************** * The contents of this file are subject to the Mozilla Public License Version 1.1 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at http://www.mozilla.org/mpl/ + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at http://www.mozilla.org/mpl/ * See the License for the specific language governing rights and limitations * under the License. * @@ -18,8 +18,8 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - ************************************************************************************** - * Contributor(s): + ************************************************************************************** + * Contributor(s): * (Open source contributors should list themselves and their modifications here). */ // Sergei Leschinski (lsu) 19 june 2010 - created the file. // Paul Meems sept. 2019 - MWGIS-183: Merge .NET and VB drawing functions @@ -39,14 +39,14 @@ STDMETHODIMP CCharts::get_Key(BSTR *pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - USES_CONVERSION; + USES_CONVERSION; *pVal = OLE2BSTR(_key); return S_OK; } STDMETHODIMP CCharts::put_Key(BSTR newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - ::SysFreeString(_key); + ::SysFreeString(_key); USES_CONVERSION; _key = OLE2BSTR(newVal); return S_OK; @@ -58,14 +58,14 @@ STDMETHODIMP CCharts::put_Key(BSTR newVal) STDMETHODIMP CCharts::get_VisibilityExpression(BSTR *pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - USES_CONVERSION; + USES_CONVERSION; *pVal = OLE2BSTR(_expression); return S_OK; } STDMETHODIMP CCharts::put_VisibilityExpression(BSTR newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - ::SysFreeString(_expression); + ::SysFreeString(_expression); USES_CONVERSION; _expression = OLE2BSTR(newVal); return S_OK; @@ -77,14 +77,14 @@ STDMETHODIMP CCharts::put_VisibilityExpression(BSTR newVal) STDMETHODIMP CCharts::get_Caption(BSTR *pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - USES_CONVERSION; + USES_CONVERSION; *pVal = OLE2BSTR(_caption); return S_OK; } STDMETHODIMP CCharts::put_Caption(BSTR newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - ::SysFreeString(_caption); + ::SysFreeString(_caption); USES_CONVERSION; _caption = OLE2BSTR(newVal); return S_OK; @@ -93,48 +93,48 @@ STDMETHODIMP CCharts::put_Caption(BSTR newVal) // ********************************************************** // get/put_Visible() // ********************************************************** -STDMETHODIMP CCharts::get_Visible( VARIANT_BOOL *retVal ) +STDMETHODIMP CCharts::get_Visible(VARIANT_BOOL *retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.visible; + *retVal = _options.visible; return S_OK; } -STDMETHODIMP CCharts::put_Visible( VARIANT_BOOL newVal ) +STDMETHODIMP CCharts::put_Visible(VARIANT_BOOL newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.visible = newVal; + _options.visible = newVal; return S_OK; } // ********************************************************** // get/put_AvoidCollisions() // ********************************************************** -STDMETHODIMP CCharts::get_AvoidCollisions( VARIANT_BOOL *retVal ) +STDMETHODIMP CCharts::get_AvoidCollisions(VARIANT_BOOL *retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.avoidCollisions; + *retVal = _options.avoidCollisions; return S_OK; } -STDMETHODIMP CCharts::put_AvoidCollisions( VARIANT_BOOL newVal ) +STDMETHODIMP CCharts::put_AvoidCollisions(VARIANT_BOOL newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.avoidCollisions = newVal; + _options.avoidCollisions = newVal; return S_OK; } // ********************************************************** // get/put_ChartType() // ********************************************************** -STDMETHODIMP CCharts::get_ChartType( tkChartType* retVal ) +STDMETHODIMP CCharts::get_ChartType(tkChartType* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.chartType; + *retVal = _options.chartType; return S_OK; } -STDMETHODIMP CCharts::put_ChartType( tkChartType newVal ) -{ +STDMETHODIMP CCharts::put_ChartType(tkChartType newVal) +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.chartType = newVal; + _options.chartType = newVal; return S_OK; } @@ -144,13 +144,13 @@ STDMETHODIMP CCharts::put_ChartType( tkChartType newVal ) STDMETHODIMP CCharts::get_BarWidth(long* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.barWidth; + *retVal = _options.barWidth; return S_OK; } STDMETHODIMP CCharts::put_BarWidth(long newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.barWidth = newVal; + _options.barWidth = newVal; return S_OK; } @@ -160,55 +160,55 @@ STDMETHODIMP CCharts::put_BarWidth(long newVal) STDMETHODIMP CCharts::get_BarHeight(long* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.barHeight; + *retVal = _options.barHeight; return S_OK; } STDMETHODIMP CCharts::put_BarHeight(long newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.barHeight = newVal; + _options.barHeight = newVal; return S_OK; } // ********************************************************** // get/put_PieChartRadius() // ********************************************************** -STDMETHODIMP CCharts::get_PieRadius (long* retVal) +STDMETHODIMP CCharts::get_PieRadius(long* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.radius; + *retVal = _options.radius; return S_OK; } -STDMETHODIMP CCharts::put_PieRadius (long newVal) +STDMETHODIMP CCharts::put_PieRadius(long newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.radius = newVal; + _options.radius = newVal; return S_OK; } // ********************************************************** // get/put_PieChartRotation() // ********************************************************** -STDMETHODIMP CCharts::get_PieRotation (double* retVal) +STDMETHODIMP CCharts::get_PieRotation(double* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.rotation; + *retVal = _options.rotation; return S_OK; } -STDMETHODIMP CCharts::put_PieRotation (double newVal) +STDMETHODIMP CCharts::put_PieRotation(double newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.rotation = newVal; + _options.rotation = newVal; return S_OK; } // ********************************************************** // get_NumBars // ********************************************************** -STDMETHODIMP CCharts::get_NumFields (long* retVal) +STDMETHODIMP CCharts::get_NumFields(long* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _bars.size(); + *retVal = _bars.size(); return S_OK; } @@ -218,7 +218,7 @@ STDMETHODIMP CCharts::get_NumFields (long* retVal) STDMETHODIMP CCharts::AddField2(long FieldIndex, OLE_COLOR Color) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - VARIANT_BOOL vbretval; + VARIANT_BOOL vbretval; this->InsertField2(_bars.size(), FieldIndex, Color, &vbretval); return S_OK; } @@ -226,16 +226,16 @@ STDMETHODIMP CCharts::AddField2(long FieldIndex, OLE_COLOR Color) STDMETHODIMP CCharts::AddField(IChartField* Field, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - if (!Field) - { - ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); - *retVal = VARIANT_FALSE; - } - else - { - _bars.push_back(Field); - Field->AddRef(); - } + if (!Field) + { + ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); + *retVal = VARIANT_FALSE; + } + else + { + _bars.push_back(Field); + Field->AddRef(); + } *retVal = VARIANT_TRUE; return S_OK; } @@ -243,28 +243,28 @@ STDMETHODIMP CCharts::AddField(IChartField* Field, VARIANT_BOOL* retVal) // ********************************************************** // InsertField2() // ********************************************************** -STDMETHODIMP CCharts::InsertField2 (long Index, long FieldIndex, OLE_COLOR Color, VARIANT_BOOL* retVal) +STDMETHODIMP CCharts::InsertField2(long Index, long FieldIndex, OLE_COLOR Color, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - if(Index < 0 || Index > (long)_bars.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - *retVal = VARIANT_FALSE; - } - else - { - IChartField* chartField = NULL; - CoCreateInstance(CLSID_ChartField,NULL,CLSCTX_INPROC_SERVER,IID_IChartField,(void**)&chartField); - if (chartField) + if (Index < 0 || Index >(long)_bars.size()) { - chartField->put_Index(FieldIndex); - chartField->put_Color(Color); + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + *retVal = VARIANT_FALSE; } + else + { + IChartField* chartField = NULL; + CoCreateInstance(CLSID_ChartField, NULL, CLSCTX_INPROC_SERVER, IID_IChartField, (void**)&chartField); + if (chartField) + { + chartField->put_Index(FieldIndex); + chartField->put_Color(Color); + } - if (Index == _bars.size()) _bars.push_back(chartField); - else _bars.insert(_bars.begin() + Index, chartField); - *retVal = VARIANT_TRUE; - } + if (Index == _bars.size()) _bars.push_back(chartField); + else _bars.insert(_bars.begin() + Index, chartField); + *retVal = VARIANT_TRUE; + } return S_OK; } @@ -274,25 +274,25 @@ STDMETHODIMP CCharts::InsertField2 (long Index, long FieldIndex, OLE_COLOR Color STDMETHODIMP CCharts::InsertField(long Index, IChartField* Field, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - if(Index < 0 || Index > (long)_bars.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - *retVal = VARIANT_FALSE; - } - else - { - if (!Field) + if (Index < 0 || Index >(long)_bars.size()) { - ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); *retVal = VARIANT_FALSE; } else { - _bars.insert(_bars.begin() + Index, Field); - Field->AddRef(); - *retVal = VARIANT_TRUE; + if (!Field) + { + ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); + *retVal = VARIANT_FALSE; + } + else + { + _bars.insert(_bars.begin() + Index, Field); + Field->AddRef(); + *retVal = VARIANT_TRUE; + } } - } return S_OK; } @@ -302,17 +302,17 @@ STDMETHODIMP CCharts::InsertField(long Index, IChartField* Field, VARIANT_BOOL* STDMETHODIMP CCharts::RemoveField(long Index, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - if(Index < 0 || Index > (long)_bars.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - *retVal = VARIANT_FALSE; - } - else - { - _bars[Index]->Release(); - _bars.erase(_bars.begin() + Index); - *retVal = VARIANT_TRUE; - } + if (Index < 0 || Index >(long)_bars.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + *retVal = VARIANT_FALSE; + } + else + { + _bars[Index]->Release(); + _bars.erase(_bars.begin() + Index); + *retVal = VARIANT_TRUE; + } return S_OK; } @@ -322,7 +322,7 @@ STDMETHODIMP CCharts::RemoveField(long Index, VARIANT_BOOL* retVal) STDMETHODIMP CCharts::MoveField(long OldIndex, long NewIndex, VARIANT_BOOL* vbretval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - ErrorMessage(tkPROPERTY_NOT_IMPLEMENTED); + ErrorMessage(tkPROPERTY_NOT_IMPLEMENTED); return S_OK; } @@ -332,17 +332,17 @@ STDMETHODIMP CCharts::MoveField(long OldIndex, long NewIndex, VARIANT_BOOL* vbre STDMETHODIMP CCharts::Generate(tkLabelPositioning Position, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - if (!_shapefile) - { - ErrorMessage(tkPARENT_SHAPEFILE_NOT_EXISTS); - *retVal = VARIANT_FALSE; - } - else - { - ((CShapefile*)_shapefile)->SetChartsPositions(Position); - _chartsExist = true; - *retVal = VARIANT_TRUE; - } + if (!_shapefile) + { + ErrorMessage(tkPARENT_SHAPEFILE_NOT_EXISTS); + *retVal = VARIANT_FALSE; + } + else + { + ((CShapefile*)_shapefile)->SetChartsPositions(Position); + _chartsExist = true; + *retVal = VARIANT_TRUE; + } return S_OK; } @@ -374,13 +374,13 @@ IShapefile* CCharts::get_ParentShapefile() STDMETHODIMP CCharts::get_Thickness(double* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.thickness; + *retVal = _options.thickness; return S_OK; } STDMETHODIMP CCharts::put_Thickness(double newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.thickness = newVal; + _options.thickness = newVal; return S_OK; } @@ -390,13 +390,13 @@ STDMETHODIMP CCharts::put_Thickness(double newVal) STDMETHODIMP CCharts::get_Tilt(double* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.tilt; + *retVal = _options.tilt; return S_OK; } STDMETHODIMP CCharts::put_Tilt(double newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.tilt = newVal; + _options.tilt = newVal; return S_OK; } @@ -406,13 +406,13 @@ STDMETHODIMP CCharts::put_Tilt(double newVal) STDMETHODIMP CCharts::get_PieRadius2(LONG* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.radius2; + *retVal = _options.radius2; return S_OK; } STDMETHODIMP CCharts::put_PieRadius2(LONG newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.radius2 = newVal; + _options.radius2 = newVal; return S_OK; } @@ -422,13 +422,13 @@ STDMETHODIMP CCharts::put_PieRadius2(LONG newVal) STDMETHODIMP CCharts::get_SizeField(LONG* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.sizeField; + *retVal = _options.sizeField; return S_OK; } STDMETHODIMP CCharts::put_SizeField(LONG newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.sizeField = newVal; + _options.sizeField = newVal; return S_OK; } @@ -438,13 +438,13 @@ STDMETHODIMP CCharts::put_SizeField(LONG newVal) STDMETHODIMP CCharts::get_NormalizationField(LONG* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.normalizationField; + *retVal = _options.normalizationField; return S_OK; } STDMETHODIMP CCharts::put_NormalizationField(LONG newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.normalizationField = newVal; + _options.normalizationField = newVal; return S_OK; } @@ -454,13 +454,13 @@ STDMETHODIMP CCharts::put_NormalizationField(LONG newVal) STDMETHODIMP CCharts::get_UseVariableRadius(VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.useVariableRadius; + *retVal = _options.useVariableRadius; return S_OK; } STDMETHODIMP CCharts::put_UseVariableRadius(VARIANT_BOOL newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.useVariableRadius = newVal?true:false; + _options.useVariableRadius = newVal ? true : false; return S_OK; } @@ -470,16 +470,16 @@ STDMETHODIMP CCharts::put_UseVariableRadius(VARIANT_BOOL newVal) STDMETHODIMP CCharts::get_Transparency(SHORT* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = (short)_options.transparency; + *retVal = (short)_options.transparency; return S_OK; } STDMETHODIMP CCharts::put_Transparency(SHORT newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - if (newVal >= 0 && newVal <= 255) - _options.transparency = newVal; - else - ErrorMessage(tkINVALID_PARAMETER_VALUE); + if (newVal >= 0 && newVal <= 255) + _options.transparency = newVal; + else + ErrorMessage(tkINVALID_PARAMETER_VALUE); return S_OK; } @@ -489,13 +489,13 @@ STDMETHODIMP CCharts::put_Transparency(SHORT newVal) STDMETHODIMP CCharts::get_LineColor(OLE_COLOR* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.lineColor; + *retVal = _options.lineColor; return S_OK; } STDMETHODIMP CCharts::put_LineColor(OLE_COLOR newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.lineColor = newVal; + _options.lineColor = newVal; return S_OK; } @@ -505,29 +505,29 @@ STDMETHODIMP CCharts::put_LineColor(OLE_COLOR newVal) STDMETHODIMP CCharts::get_Use3DMode(VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.use3Dmode; + *retVal = _options.use3Dmode; return S_OK; } STDMETHODIMP CCharts::put_Use3DMode(VARIANT_BOOL newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.use3Dmode = newVal?true:false; + _options.use3Dmode = newVal ? true : false; return S_OK; } // ********************************************************** // VerticalPosition // ********************************************************** -STDMETHODIMP CCharts::get_VerticalPosition (tkVerticalPosition* retVal) +STDMETHODIMP CCharts::get_VerticalPosition(tkVerticalPosition* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _options.verticalPosition; + *retVal = _options.verticalPosition; return S_OK; } -STDMETHODIMP CCharts::put_VerticalPosition (tkVerticalPosition newVal) +STDMETHODIMP CCharts::put_VerticalPosition(tkVerticalPosition newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _options.verticalPosition = newVal; + _options.verticalPosition = newVal; return S_OK; } @@ -537,53 +537,53 @@ STDMETHODIMP CCharts::put_VerticalPosition (tkVerticalPosition newVal) STDMETHODIMP CCharts::get_Chart(long ShapeIndex, IChart** retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - - if (!_shapefile) - { - ErrorMessage(tkPARENT_SHAPEFILE_NOT_EXISTS); - *retVal = NULL; - return S_OK; - } - else - { - std::vector* positions = ((CShapefile*)_shapefile)->get_ShapeVector(); - if ( ShapeIndex < 0 || ShapeIndex > (long)positions->size()) + + if (!_shapefile) { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + ErrorMessage(tkPARENT_SHAPEFILE_NOT_EXISTS); *retVal = NULL; return S_OK; } else { - IChart* chart = NULL; - CoCreateInstance(CLSID_Chart,NULL,CLSCTX_INPROC_SERVER,IID_IChart,(void**)&chart); - if (chart) + std::vector* positions = ((CShapefile*)_shapefile)->get_ShapeVector(); + if (ShapeIndex < 0 || ShapeIndex >(long)positions->size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + *retVal = NULL; + return S_OK; + } + else { - ShapeRecord* data = (*positions)[ShapeIndex]; - ((CChart*)chart)->put_ChartData(reinterpret_cast(data->chart)); + IChart* chart = NULL; + CoCreateInstance(CLSID_Chart, NULL, CLSCTX_INPROC_SERVER, IID_IChart, (void**)&chart); + if (chart) + { + ShapeRecord* data = (*positions)[ShapeIndex]; + ((CChart*)chart)->put_ChartData(reinterpret_cast(data->chart)); + } + *retVal = chart; } - *retVal = chart; } - } return S_OK; } // ********************************************************** // get_Field // ********************************************************** -STDMETHODIMP CCharts::get_Field (long FieldIndex, IChartField** retVal) +STDMETHODIMP CCharts::get_Field(long FieldIndex, IChartField** retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - - if(FieldIndex < 0 || FieldIndex > (long)_bars.size() - 1) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - *retVal = _bars[FieldIndex]; - (*retVal)->AddRef(); - } + + if (FieldIndex < 0 || FieldIndex >(long)_bars.size() - 1) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + *retVal = _bars[FieldIndex]; + (*retVal)->AddRef(); + } return S_OK; } @@ -593,8 +593,8 @@ STDMETHODIMP CCharts::get_Field (long FieldIndex, IChartField** retVal) STDMETHODIMP CCharts::get_LastErrorCode(long *pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - - *pVal = _lastErrorCode; + + *pVal = _lastErrorCode; _lastErrorCode = tkNO_ERROR; return S_OK; @@ -606,8 +606,8 @@ STDMETHODIMP CCharts::get_LastErrorCode(long *pVal) STDMETHODIMP CCharts::get_ErrorMsg(long ErrorCode, BSTR *pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - - USES_CONVERSION; + + USES_CONVERSION; *pVal = A2BSTR(ErrorMsg(ErrorCode)); return S_OK; @@ -619,8 +619,8 @@ STDMETHODIMP CCharts::get_ErrorMsg(long ErrorCode, BSTR *pVal) STDMETHODIMP CCharts::get_GlobalCallback(ICallback **pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *pVal = _globalCallback; - if( _globalCallback ) + *pVal = _globalCallback; + if (_globalCallback) { _globalCallback->AddRef(); } @@ -629,7 +629,7 @@ STDMETHODIMP CCharts::get_GlobalCallback(ICallback **pVal) STDMETHODIMP CCharts::put_GlobalCallback(ICallback *newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - ComHelper::SetRef(newVal, (IDispatch**)&_globalCallback); + ComHelper::SetRef(newVal, (IDispatch**)&_globalCallback); return S_OK; } @@ -639,24 +639,24 @@ STDMETHODIMP CCharts::put_GlobalCallback(ICallback *newVal) STDMETHODIMP CCharts::get_Count(long *retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - if(!_shapefile) - { - ErrorMessage(tkPARENT_SHAPEFILE_NOT_EXISTS); - *retVal = 0; - } - else - { - if (_chartsExist) + if (!_shapefile) { - long numShapes; - _shapefile->get_NumShapes(&numShapes); - *retVal = numShapes; + ErrorMessage(tkPARENT_SHAPEFILE_NOT_EXISTS); + *retVal = 0; } else { - *retVal = 0; + if (_chartsExist) + { + long numShapes; + _shapefile->get_NumShapes(&numShapes); + *retVal = numShapes; + } + else + { + *retVal = 0; + } } - } return S_OK; } @@ -666,10 +666,10 @@ STDMETHODIMP CCharts::get_Count(long *retVal) STDMETHODIMP CCharts::ClearFields() { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - for (unsigned int i = 0; i < _bars.size(); i++) - { - _bars[i]->Release(); - } + for (unsigned int i = 0; i < _bars.size(); i++) + { + _bars[i]->Release(); + } _bars.clear(); return S_OK; } @@ -680,10 +680,9 @@ STDMETHODIMP CCharts::ClearFields() STDMETHODIMP CCharts::Clear() { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - IShapefile* sf = this->get_ParentShapefile(); + IShapefile* sf = this->get_ParentShapefile(); if (sf) { - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); std::vector* data = ((CShapefile*)sf)->get_ShapeVector(); for (unsigned int i = 0; i < data->size(); i++) { @@ -706,13 +705,13 @@ STDMETHODIMP CCharts::Clear() STDMETHODIMP CCharts::DrawChart(int hdc, float x, float y, VARIANT_BOOL hideLabels, OLE_COLOR backColor, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - - if (!hdc) - { - ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); - return S_OK; - } - + + if (!hdc) + { + ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); + return S_OK; + } + CDC* dc = CDC::FromHandle((HDC)hdc); *retVal = DrawChartCore(dc, x, y, hideLabels, backColor); return S_OK; @@ -740,7 +739,7 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide ErrorMessage(tkFAILED_TO_OBTAIN_DC); return VARIANT_FALSE; } - + long numBars; this->get_NumFields(&numBars); bool noFields = false; @@ -753,24 +752,24 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide // initializing graphics Gdiplus::Graphics g(dc->GetSafeHdc()); - long alpha =_options.transparency << 24; + long alpha = _options.transparency << 24; Gdiplus::Pen pen(Utility::OleColor2GdiPlus(_options.lineColor, (BYTE)_options.transparency)); Gdiplus::Color clr = Utility::OleColor2GdiPlus(backColor, 255); Gdiplus::SolidBrush brushBackground(clr); Gdiplus::Pen penBackground(clr); - + CFont* oldFont = NULL; CFont fnt; CBrush brushFrame(_options.valuesFrameColor); - + // values font initialization bool vertical = (_options.valuesStyle == vsVertical); CString sFormat = "%g"; // format for numbers if (_options.valuesVisible && !hideLabels) { - LOGFONT lf; + LOGFONT lf; CString s(_options.valuesFontName); fnt.CreatePointFont(_options.valuesFontSize * 10, s); @@ -780,16 +779,16 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide { lf.lfEscapement = 900; } - + dc->SetTextColor(_options.valuesFontColor); lf.lfItalic = (BYTE)_options.valuesFontItalic; - if (_options.valuesFontBold) + if (_options.valuesFontBold) lf.lfWeight = FW_BOLD; - else + else lf.lfWeight = 0; - + fnt.DeleteObject(); fnt.CreateFontIndirectA(&lf); oldFont = dc->SelectObject(&fnt); @@ -803,31 +802,31 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide // drawing pie charts if (_options.chartType == chtPieChart) { - Gdiplus::REAL pieThickness = (Gdiplus::REAL)(_options.thickness *_options.tilt/90.0); - + Gdiplus::REAL pieThickness = (Gdiplus::REAL)(_options.thickness *_options.tilt / 90.0); + Gdiplus::REAL pieHeight; if (_options.use3Dmode) - pieHeight = (Gdiplus::REAL)(_options.radius * (1.0 -_options.tilt/90.0) * 2.0); + pieHeight = (Gdiplus::REAL)(_options.radius * (1.0 - _options.tilt / 90.0) * 2.0); else - pieHeight =(Gdiplus::REAL)(_options.radius * 2.0); + pieHeight = (Gdiplus::REAL)(_options.radius * 2.0); + + Gdiplus::REAL pieWidth = (Gdiplus::REAL)(_options.radius * 2.0); - Gdiplus::REAL pieWidth =(Gdiplus::REAL)(_options.radius * 2.0); - double sum = 0.0; std::vector values; - + for (int j = 0; j < numBars; j++) { - values.push_back(100.0/(double)numBars); + values.push_back(100.0 / (double)numBars); sum += values[j]; } - + Gdiplus::REAL xStart = (Gdiplus::REAL)x; //0 Gdiplus::REAL yStart = (Gdiplus::REAL)y; //0 - + Gdiplus::REAL startAngle = 0.0, sweepAngle = 0.0; Gdiplus::GraphicsPath path; - + for (int j = 0; j < numBars; j++) { // retrieving color @@ -842,27 +841,27 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide this->get_Field(j, &fld); fld->get_Color(&color); } - + // initializing brushes Gdiplus::Color clr(alpha | BGR_TO_RGB(color)); Gdiplus::Color clrDimmed = Utility::ChangeBrightness(color, -100, alpha); Gdiplus::SolidBrush brush(clr); Gdiplus::SolidBrush brushDimmed(clrDimmed); - sweepAngle = (Gdiplus::REAL)(values[j]/sum * 360.0); + sweepAngle = (Gdiplus::REAL)(values[j] / sum * 360.0); g.FillPie(&brushBackground, xStart, yStart, pieWidth, pieHeight, startAngle, sweepAngle); g.FillPie(&brush, xStart, yStart, pieWidth, pieHeight, startAngle, sweepAngle); path.AddPie(xStart, yStart, pieWidth, pieHeight, startAngle, sweepAngle); - + // 3D mode - if ( startAngle < 180.0 &&_options.use3Dmode) + if (startAngle < 180.0 &&_options.use3Dmode) { Gdiplus::GraphicsPath pathBottom; if (startAngle + sweepAngle > 180.0) pathBottom.AddArc(xStart, yStart + pieThickness, pieWidth, pieHeight, startAngle, 180 - startAngle); else pathBottom.AddArc(xStart, yStart + pieThickness, pieWidth, pieHeight, startAngle, sweepAngle); - + Gdiplus::PathData pathData; pathBottom.GetPathData(&pathData); Gdiplus::PointF* pntStart, *pntEnd; @@ -879,9 +878,9 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide } else pathBottom.AddArc(xStart, yStart, pieWidth, pieHeight, startAngle + sweepAngle, -sweepAngle); - + pathBottom.AddLine(pntStart->X, pntStart->Y - (Gdiplus::REAL)pieThickness, pntStart->X, pntStart->Y); - + g.FillPath(&brushBackground, &pathBottom); g.FillPath(&brushDimmed, &pathBottom); g.DrawPath(&penBackground, &pathBottom); @@ -897,12 +896,12 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide { CCollisionList collisionList; startAngle = 0.0; - xStart += pieWidth/2.0f; - yStart += pieHeight/2.0f; - + xStart += pieWidth / 2.0f; + yStart += pieHeight / 2.0f; + for (int j = 0; j < numBars; j++) { - sweepAngle = (Gdiplus::REAL)(values[j]/sum * 360.0); + sweepAngle = (Gdiplus::REAL)(values[j] / sum * 360.0); // label drawing ValueRectangle value; @@ -910,39 +909,39 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide value.string = Utility::FormatNumber(values[j], CString("%g")); dc->DrawText(value.string, rect, DT_CALCRECT); // add alignment - - Gdiplus::REAL labelAngle = startAngle + sweepAngle/2.0f + 90.0f; + + Gdiplus::REAL labelAngle = startAngle + sweepAngle / 2.0f + 90.0f; if (labelAngle > 360.0f) { labelAngle = labelAngle - 360.0f; } - - int x = (int)(xStart + sin(labelAngle/180.0 * pi_) * _options.radius); - int y = (int)(yStart - cos(labelAngle/180.0 * pi_) * _options.radius); - + + int x = (int)(xStart + sin(labelAngle / 180.0 * pi_) * _options.radius); + int y = (int)(yStart - cos(labelAngle / 180.0 * pi_) * _options.radius); + if (labelAngle >= 0.0 && labelAngle <= 180.0) { - x += rect->Width()/2; + x += rect->Width() / 2; } else { - x -= rect->Width()/2; + x -= rect->Width() / 2; } - if (labelAngle >= 90.0 && labelAngle <= 270.0 ) + if (labelAngle >= 90.0 && labelAngle <= 270.0) { - y += rect->Height()/2; + y += rect->Height() / 2; } else { - y -= rect->Height()/2; + y -= rect->Height() / 2; } - + startAngle += sweepAngle; - - rect->MoveToX(x - rect->Width()/2); - rect->MoveToY(y - rect->Height()/2); - + + rect->MoveToX(x - rect->Width() / 2); + rect->MoveToY(y - rect->Height() / 2); + if (collisionList.HaveCollision(*rect)) { continue; @@ -957,8 +956,8 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide if (_options.valuesFrameVisible) { CBrush* oldBrush = dc->SelectObject(&brushFrame); - - CRect r(rect->left -3, rect->top, rect->right +2, rect->bottom); + + CRect r(rect->left - 3, rect->top, rect->right + 2, rect->bottom); dc->Rectangle(r); dc->SelectObject(oldBrush); } @@ -972,25 +971,25 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide // ------------------------------------------------------------- // Bar charts drawing // ------------------------------------------------------------- - else if(_options.chartType == chtBarChart) + else if (_options.chartType == chtBarChart) { Gdiplus::PointF points[5]; - + std::vector values; - + for (int j = 1; j <= numBars; j++) { values.push_back(j); } - + double minValue = 1; double maxValue = numBars; - + int barHeight = _options.barHeight; // > 30 ? 30 : _options.barHeight; - double maxHeight = (double)barHeight; + double maxHeight = (double)barHeight; int xStart = (int)x; - int yStart = (int)y + (_options.use3Dmode?(int)(_options.thickness * _options.tilt/90.0 + 2):0); + int yStart = (int)y + (_options.use3Dmode ? (int)(_options.thickness * _options.tilt / 90.0 + 2) : 0); double angle = 45.0; @@ -1010,35 +1009,35 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide fld->Release(); fld = NULL; } - + // initializing brushes Gdiplus::Color clr(alpha | BGR_TO_RGB(color)); Gdiplus::Color clrDimmed = Utility::ChangeBrightness(color, -100, alpha); Gdiplus::SolidBrush brush(clr); Gdiplus::SolidBrush brushDimmed(clrDimmed); - - int height = int((double)barHeight/maxValue * values[j]); + + int height = int((double)barHeight / maxValue * values[j]); int offsetY = barHeight - height + yStart; - - if ( height != 0 ) + + if (height != 0) { g.FillRectangle(&brushBackground, xStart, offsetY, _options.barWidth, height); g.FillRectangle(&brush, xStart, offsetY, _options.barWidth, height); - + g.DrawRectangle(&penBackground, xStart, offsetY, _options.barWidth, height); g.DrawRectangle(&pen, xStart, offsetY, _options.barWidth, height); - + // 3D mode - if ( _options.use3Dmode ) + if (_options.use3Dmode) { points[0].X = (Gdiplus::REAL)xStart; - points[1].X = (Gdiplus::REAL)(xStart + sin(angle/180*pi_) * _options.thickness); + points[1].X = (Gdiplus::REAL)(xStart + sin(angle / 180 * pi_) * _options.thickness); points[2].X = (Gdiplus::REAL)points[1].X + _options.barWidth; points[3].X = (Gdiplus::REAL)xStart + _options.barWidth; points[4].X = (Gdiplus::REAL)xStart; points[0].Y = (Gdiplus::REAL)offsetY; - points[1].Y = (Gdiplus::REAL)(offsetY - cos(angle/180*pi_) * _options.thickness); + points[1].Y = (Gdiplus::REAL)(offsetY - cos(angle / 180 * pi_) * _options.thickness); points[2].Y = (Gdiplus::REAL)points[1].Y; points[3].Y = (Gdiplus::REAL)offsetY; points[4].Y = (Gdiplus::REAL)offsetY; @@ -1049,13 +1048,13 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide g.FillPolygon(&brushDimmed, points, 5); points[0].X = (Gdiplus::REAL)xStart + _options.barWidth; - points[1].X = (Gdiplus::REAL)(points[0].X + sin(angle/180*pi_) * _options.thickness); + points[1].X = (Gdiplus::REAL)(points[0].X + sin(angle / 180 * pi_) * _options.thickness); points[2].X = (Gdiplus::REAL)points[1].X; points[3].X = (Gdiplus::REAL)points[0].X; points[4].X = (Gdiplus::REAL)points[0].X; points[0].Y = (Gdiplus::REAL)offsetY; - points[1].Y = (Gdiplus::REAL)(points[0].Y - cos(angle/180*pi_) * _options.thickness); + points[1].Y = (Gdiplus::REAL)(points[0].Y - cos(angle / 180 * pi_) * _options.thickness); points[2].Y = (Gdiplus::REAL)points[1].Y + height; points[3].Y = (Gdiplus::REAL)points[0].Y + height; points[4].Y = (Gdiplus::REAL)points[0].Y; @@ -1068,25 +1067,25 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide } xStart += _options.barWidth; } - + // drawing the labels std::vector labels; if (_options.valuesVisible && !hideLabels) { - int xAdd = (int)(sin(45.0/180*pi_) * _options.thickness); - + int xAdd = (int)(sin(45.0 / 180 * pi_) * _options.thickness); + xStart = int(x); //- numBars * _options.barWidth/2.0); yStart = int(y + maxHeight); int x, y; - + // calculating position of drawing for (int j = 0; j < numBars; j++) { - int height = int((double)barHeight/maxValue * values[j]); - if ( height != 0 ) + int height = int((double)barHeight / maxValue * values[j]); + if (height != 0) { CString s = Utility::FormatNumber(values[j], sFormat); - + CRect* rect = new CRect(); dc->DrawText(s, rect, DT_CALCRECT); @@ -1094,17 +1093,17 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide { rect->MoveToY(yStart - rect->Height() - height - 3); - if (j == 0 ) + if (j == 0) { - rect->MoveToX(xStart + _options.barWidth/2 - rect->Width()); + rect->MoveToX(xStart + _options.barWidth / 2 - rect->Width()); } else if (j == numBars - 1) { - rect->MoveToX(xStart + _options.barWidth/2); + rect->MoveToX(xStart + _options.barWidth / 2); } else { - rect->MoveToX(xStart + _options.barWidth/2 - rect->Width()/2); + rect->MoveToX(xStart + _options.barWidth / 2 - rect->Width() / 2); } } else @@ -1115,22 +1114,22 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide rect->bottom = 0; rect->left = 0; rect->right = ht; - rect->top = - wd; - - x = xStart + _options.barWidth/2 - rect->Width()/2 + xAdd/2; + rect->top = -wd; + + x = xStart + _options.barWidth / 2 - rect->Width() / 2 + xAdd / 2; y = yStart - rect->Height() - height - 6; - + rect->MoveToXY(x, y); } - + // we shall store the label, to keep the collision list clean ValueRectangle value; value.string = s; - + // drawing frame if (!vertical) { - CRect r(rect->left-2, rect->top, rect->right + 2, rect->bottom); + CRect r(rect->left - 2, rect->top, rect->right + 2, rect->bottom); value.rect = r; } else @@ -1139,7 +1138,7 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide value.rect = r; } labels.push_back(value); - + } xStart += _options.barWidth; } // numBars @@ -1159,7 +1158,7 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide if (!vertical) { - dc->DrawText(labels[j].string, rect, DT_CENTER|DT_VCENTER); + dc->DrawText(labels[j].string, rect, DT_CENTER | DT_VCENTER); } else { @@ -1168,7 +1167,7 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide } } // valuesVisible } - + if (_options.valuesVisible) { dc->SelectObject(oldFont); @@ -1184,17 +1183,17 @@ VARIANT_BOOL CCharts::DrawChartCore(CDC* dc, float x, float y, VARIANT_BOOL hide STDMETHODIMP CCharts::get_IconWidth(long *retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - if (_options.chartType == chtBarChart) - { - int barCount = _bars.size() == 0?1:_bars.size(); - *retVal = _options.barWidth * barCount + 2; - if (_options.use3Dmode) - *retVal += int(sqrt(2.0f)/2.0 * _options.thickness); // 45 degrees - } - else - { - *retVal = _options.radius * 2 + 2; - } + if (_options.chartType == chtBarChart) + { + int barCount = _bars.size() == 0 ? 1 : _bars.size(); + *retVal = _options.barWidth * barCount + 2; + if (_options.use3Dmode) + *retVal += int(sqrt(2.0f) / 2.0 * _options.thickness); // 45 degrees + } + else + { + *retVal = _options.radius * 2 + 2; + } return S_OK; } @@ -1205,39 +1204,39 @@ STDMETHODIMP CCharts::get_IconHeight(long *retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) if (_options.chartType == chtBarChart) - { - *retVal = _options.barHeight + 2; - if (_options.use3Dmode) - *retVal += (int)(sqrt(2.0f)/2.0 * _options.thickness); - } - else - { - if (_options.use3Dmode) - *retVal = (long)(_options.radius * (1.0 -_options.tilt/90.0) * 2.0 + _options.thickness * _options.tilt/90.0 + 2); + { + *retVal = _options.barHeight + 2; + if (_options.use3Dmode) + *retVal += (int)(sqrt(2.0f) / 2.0 * _options.thickness); + } else - *retVal = (long)(_options.radius * 2.0 + 2); - } + { + if (_options.use3Dmode) + *retVal = (long)(_options.radius * (1.0 - _options.tilt / 90.0) * 2.0 + _options.thickness * _options.tilt / 90.0 + 2); + else + *retVal = (long)(_options.radius * 2.0 + 2); + } return S_OK; } // ***************************************************************** // FontName() // ***************************************************************** -STDMETHODIMP CCharts::get_ValuesFontName(BSTR* retval) +STDMETHODIMP CCharts::get_ValuesFontName(BSTR* retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - USES_CONVERSION; - *retval = OLE2BSTR(_options.valuesFontName); + USES_CONVERSION; + *retval = OLE2BSTR(_options.valuesFontName); return S_OK; -}; -STDMETHODIMP CCharts::put_ValuesFontName(BSTR newVal) +}; +STDMETHODIMP CCharts::put_ValuesFontName(BSTR newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - USES_CONVERSION; + USES_CONVERSION; ::SysFreeString(_options.valuesFontName); _options.valuesFontName = OLE2BSTR(newVal); return S_OK; -}; +}; // ***************************************************************** // Select() @@ -1255,12 +1254,12 @@ STDMETHODIMP CCharts::Select(IExtents* BoundingBox, long Tolerance, SelectMode S double xMin, yMin, zMin, xMax, yMax, zMax; BoundingBox->GetBounds(&xMin, &yMin, &zMin, &xMax, &yMax, &zMax); - CRect box(int(xMin - Tolerance/2), int(yMin - Tolerance/2), int(xMax + Tolerance/2), int(yMax + Tolerance/2)); - + CRect box(int(xMin - Tolerance / 2), int(yMin - Tolerance / 2), int(xMax + Tolerance / 2), int(yMax + Tolerance / 2)); + vector results; - + IUtils* utils = NULL; - CoCreateInstance(CLSID_Utils,NULL,CLSCTX_INPROC_SERVER,IID_IUtils,(void**)&utils); + CoCreateInstance(CLSID_Utils, NULL, CLSCTX_INPROC_SERVER, IID_IUtils, (void**)&utils); long numShapes; _shapefile->get_NumShapes(&numShapes); @@ -1282,7 +1281,7 @@ STDMETHODIMP CCharts::Select(IExtents* BoundingBox, long Tolerance, SelectMode S results.push_back(i); } } - + } utils->Release(); @@ -1299,7 +1298,7 @@ STDMETHODIMP CCharts::Select(IExtents* BoundingBox, long Tolerance, SelectMode S STDMETHODIMP CCharts::Serialize(BSTR* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CPLXMLNode* psTree = SerializeCore("ChartsClass"); + CPLXMLNode* psTree = SerializeCore("ChartsClass"); Utility::SerializeAndDestroyXmlTree(psTree, retVal); return S_OK; } @@ -1310,8 +1309,8 @@ STDMETHODIMP CCharts::Serialize(BSTR* retVal) CPLXMLNode* CCharts::SerializeCore(CString ElementName) { USES_CONVERSION; - - CPLXMLNode* psTree = CPLCreateXMLNode( NULL, CXT_Element, "ChartsClass"); + + CPLXMLNode* psTree = CPLCreateXMLNode(NULL, CXT_Element, "ChartsClass"); CString str; // fields @@ -1323,18 +1322,18 @@ CPLXMLNode* CCharts::SerializeCore(CString ElementName) for (unsigned int i = 0; i < _bars.size(); i++) { CPLXMLNode* psNode = CPLCreateXMLNode(psFields, CXT_Element, "ChartFieldClass"); - + // name CComBSTR name; _bars[i]->get_Name(&name); str = OLE2CA(name); Utility::CPLCreateXMLAttributeAndValue(psNode, "Name", str); - + // color OLE_COLOR color; _bars[i]->get_Color(&color); Utility::CPLCreateXMLAttributeAndValue(psNode, "Color", CPLString().Printf("%d", color)); - + // index long index; _bars[i]->get_Index(&index); @@ -1345,10 +1344,10 @@ CPLXMLNode* CCharts::SerializeCore(CString ElementName) // serializing data if (_chartsExist) - { + { if (_savingMode == modeStandard) { - CPLXMLNode* nodeCharts = this->SerializeChartData("Charts" ); + CPLXMLNode* nodeCharts = this->SerializeChartData("Charts"); if (nodeCharts) { CPLAddXMLChild(psTree, nodeCharts); @@ -1367,10 +1366,10 @@ CPLXMLNode* CCharts::SerializeCore(CString ElementName) _shapefile->get_Filename(&name); CString path = Utility::GetPathWOExtension(OLE2CA(name)); path += ".chart"; - + if (Utility::FileExists(path) && _savingMode == modeXMLOverwrite) { - if( remove( path ) != 0 ) + if (remove(path) != 0) { ErrorMessage(tkCANT_DELETE_FILE); } @@ -1399,13 +1398,13 @@ CPLXMLNode* CCharts::SerializeCore(CString ElementName) } ChartOptions opt; // to compare with default settings - + if (_options.avoidCollisions != opt.avoidCollisions) Utility::CPLCreateXMLAttributeAndValue(psTree, "AvoidCollisions", CPLString().Printf("%d", (int)_options.avoidCollisions)); if (_options.barHeight != opt.barHeight) Utility::CPLCreateXMLAttributeAndValue(psTree, "BarHeight", CPLString().Printf("%d", _options.barHeight)); - + if (_options.barWidth != opt.barWidth) Utility::CPLCreateXMLAttributeAndValue(psTree, "BarWidth", CPLString().Printf("%d", _options.barWidth)); @@ -1435,25 +1434,25 @@ CPLXMLNode* CCharts::SerializeCore(CString ElementName) if (_options.tilt != opt.tilt) Utility::CPLCreateXMLAttributeAndValue(psTree, "Tilt", CPLString().Printf("%f", _options.tilt)); - + if (_options.transparency != opt.transparency) Utility::CPLCreateXMLAttributeAndValue(psTree, "Transparency", CPLString().Printf("%d", _options.transparency)); - + if (_options.use3Dmode != opt.use3Dmode) Utility::CPLCreateXMLAttributeAndValue(psTree, "Use3Dmode", CPLString().Printf("%d", (int)_options.use3Dmode)); - + if (_options.useVariableRadius != opt.useVariableRadius) Utility::CPLCreateXMLAttributeAndValue(psTree, "UseVariableRadius", CPLString().Printf("%d", (int)_options.useVariableRadius)); - + if (_options.valuesFontBold != opt.valuesFontBold) Utility::CPLCreateXMLAttributeAndValue(psTree, "ValuesFontBold", CPLString().Printf("%d", (int)_options.valuesFontBold)); - + if (_options.valuesFontColor != opt.valuesFontColor) Utility::CPLCreateXMLAttributeAndValue(psTree, "ValuesFontColor", CPLString().Printf("%d", _options.valuesFontColor)); - + if (_options.valuesFontItalic != opt.valuesFontItalic) Utility::CPLCreateXMLAttributeAndValue(psTree, "ValuesFontItalic", CPLString().Printf("%d", (int)_options.valuesFontItalic)); - + str = OLE2A(_options.valuesFontName); if (str != OLE2A(opt.valuesFontName)) Utility::CPLCreateXMLAttributeAndValue(psTree, "ValuesFontName", str); @@ -1466,20 +1465,20 @@ CPLXMLNode* CCharts::SerializeCore(CString ElementName) if (_options.valuesFrameVisible != opt.valuesFrameVisible) Utility::CPLCreateXMLAttributeAndValue(psTree, "ValuesFrameVisible", CPLString().Printf("%d", (int)_options.valuesFrameVisible)); - + if (_options.valuesStyle != opt.valuesStyle) Utility::CPLCreateXMLAttributeAndValue(psTree, "ValuesStyle", CPLString().Printf("%d", (int)_options.valuesStyle)); - + if (_options.valuesVisible != opt.valuesVisible) Utility::CPLCreateXMLAttributeAndValue(psTree, "ValuesVisible", CPLString().Printf("%d", (int)_options.valuesVisible)); - + if (_options.verticalPosition != opt.verticalPosition) Utility::CPLCreateXMLAttributeAndValue(psTree, "VerticalPosition", CPLString().Printf("%d", (int)_options.verticalPosition)); - + if (_options.visible != opt.visible) Utility::CPLCreateXMLAttributeAndValue(psTree, "Visible", CPLString().Printf("%d", (int)_options.visible)); - if (_savingMode != modeXML) + if (_savingMode != modeXML) Utility::CPLCreateXMLAttributeAndValue(psTree, "SavingMode", CPLString().Printf("%d", (int)_savingMode)); return psTree; @@ -1492,16 +1491,16 @@ bool CCharts::DeserializeCore(CPLXMLNode* node) { if (!node) return false; - + // restoring fields this->ClearFields(); - + // we don't touch charts in this mode if (_savingMode != modeNone) { this->Clear(); } - + CString s; CPLXMLNode* nodeFields = CPLGetXMLNode(node, "ChartFields"); @@ -1513,20 +1512,20 @@ bool CCharts::DeserializeCore(CPLXMLNode* node) if (strcmp(node->pszValue, "ChartFieldClass") == 0) { IChartField* field = NULL; - CoCreateInstance(CLSID_ChartField,NULL,CLSCTX_INPROC_SERVER,IID_IChartField,(void**)&field); - + CoCreateInstance(CLSID_ChartField, NULL, CLSCTX_INPROC_SERVER, IID_IChartField, (void**)&field); + // name - s = CPLGetXMLValue( node, "Name", NULL ); - CComBSTR vbstr( s ); + s = CPLGetXMLValue(node, "Name", NULL); + CComBSTR vbstr(s); field->put_Name(vbstr); - s = CPLGetXMLValue( node, "Color", NULL ); - OLE_COLOR color = atoi( s ); - field->put_Color( color ); + s = CPLGetXMLValue(node, "Color", NULL); + OLE_COLOR color = atoi(s); + field->put_Color(color); - s = CPLGetXMLValue( node, "Index", NULL ); - long index = atoi( s ); - field->put_Index( index ); + s = CPLGetXMLValue(node, "Index", NULL); + long index = atoi(s); + field->put_Index(index); VARIANT_BOOL vbretval; this->AddField(field, &vbretval); @@ -1534,13 +1533,13 @@ bool CCharts::DeserializeCore(CPLXMLNode* node) field->Release(); } node = node->psNext; - } + } } - + // restoring labels if (_savingMode == modeStandard) { - node = CPLGetXMLNode( node, "Charts" ); + node = CPLGetXMLNode(node, "Charts"); if (node) { this->DeserializeChartData(node); @@ -1552,7 +1551,7 @@ bool CCharts::DeserializeCore(CPLXMLNode* node) { tkShapefileSourceType sourceType; _shapefile->get_SourceType(&sourceType); - + if (sourceType == sstDiskBased) { // constructing the name of .lbl file @@ -1561,7 +1560,7 @@ bool CCharts::DeserializeCore(CPLXMLNode* node) USES_CONVERSION; CString path = Utility::GetPathWOExtension(OLE2CA(name)); path += ".chart"; - + // restoring labels if (Utility::FileExists(path)) { @@ -1576,90 +1575,90 @@ bool CCharts::DeserializeCore(CPLXMLNode* node) ChartOptions opt; // for default set of options // start labels specific options - s = CPLGetXMLValue( node, "AvoidCollisions", NULL ); + s = CPLGetXMLValue(node, "AvoidCollisions", NULL); _options.avoidCollisions = (s != "") ? (VARIANT_BOOL)atoi(s.GetString()) : opt.avoidCollisions; - s = CPLGetXMLValue( node, "BarHeight", NULL ); + s = CPLGetXMLValue(node, "BarHeight", NULL); _options.barHeight = (s != "") ? atoi(s.GetString()) : opt.barHeight; - s = CPLGetXMLValue( node, "BarWidth", NULL ); + s = CPLGetXMLValue(node, "BarWidth", NULL); _options.barWidth = (s != "") ? atoi(s.GetString()) : opt.barWidth; - - s = CPLGetXMLValue( node, "ChartType", NULL ); + + s = CPLGetXMLValue(node, "ChartType", NULL); _options.chartType = (s != "") ? (tkChartType)atoi(s.GetString()) : opt.chartType; - - s = CPLGetXMLValue( node, "LineColor", NULL ); + + s = CPLGetXMLValue(node, "LineColor", NULL); _options.lineColor = (s != "") ? (OLE_COLOR)atoi(s.GetString()) : opt.lineColor; - s = CPLGetXMLValue( node, "NormalizationField", NULL ); + s = CPLGetXMLValue(node, "NormalizationField", NULL); _options.normalizationField = (s != "") ? atoi(s.GetString()) : opt.normalizationField; - - s = CPLGetXMLValue( node, "Radius", NULL ); + + s = CPLGetXMLValue(node, "Radius", NULL); _options.radius = (s != "") ? atoi(s.GetString()) : opt.radius; - - s = CPLGetXMLValue( node, "Radius2", NULL ); + + s = CPLGetXMLValue(node, "Radius2", NULL); _options.radius2 = (s != "") ? atoi(s.GetString()) : opt.radius2; - - s = CPLGetXMLValue( node, "Rotation", NULL ); + + s = CPLGetXMLValue(node, "Rotation", NULL); _options.rotation = (s != "") ? atoi(s.GetString()) : opt.rotation; - s = CPLGetXMLValue( node, "SizeField", NULL ); + s = CPLGetXMLValue(node, "SizeField", NULL); _options.sizeField = (s != "") ? atoi(s.GetString()) : opt.sizeField; - s = CPLGetXMLValue( node, "Thickness", NULL ); + s = CPLGetXMLValue(node, "Thickness", NULL); _options.thickness = (s != "") ? Utility::atof_custom(s) : opt.thickness; - s = CPLGetXMLValue( node, "Tilt", NULL ); + s = CPLGetXMLValue(node, "Tilt", NULL); _options.tilt = (s != "") ? Utility::atof_custom(s) : opt.tilt; - s = CPLGetXMLValue( node, "Transparency", NULL ); + s = CPLGetXMLValue(node, "Transparency", NULL); _options.transparency = (s != "") ? atoi(s) : opt.transparency; - s = CPLGetXMLValue( node, "Use3Dmode", NULL ); + s = CPLGetXMLValue(node, "Use3Dmode", NULL); _options.use3Dmode = (s != "") ? (atoi(s) == 0 ? false : true) : opt.use3Dmode; - s = CPLGetXMLValue( node, "UseVariableRadius", NULL ); + s = CPLGetXMLValue(node, "UseVariableRadius", NULL); _options.useVariableRadius = (s != "") ? (atoi(s.GetString()) == 0 ? false : true) : opt.useVariableRadius; - s = CPLGetXMLValue( node, "ValuesFontBold", NULL ); + s = CPLGetXMLValue(node, "ValuesFontBold", NULL); _options.valuesFontBold = (s != "") ? (VARIANT_BOOL)atoi(s.GetString()) : opt.valuesFontBold; - s = CPLGetXMLValue( node, "ValuesFontColor", NULL ); + s = CPLGetXMLValue(node, "ValuesFontColor", NULL); _options.valuesFontColor = (s != "") ? (OLE_COLOR)atoi(s.GetString()) : opt.valuesFontColor; - s = CPLGetXMLValue( node, "ValuesFontItalic", NULL ); + s = CPLGetXMLValue(node, "ValuesFontItalic", NULL); _options.valuesFontItalic = (s != "") ? (VARIANT_BOOL)atoi(s.GetString()) : opt.valuesFontItalic; - s = CPLGetXMLValue( node, "ValuesFontName", NULL ); + s = CPLGetXMLValue(node, "ValuesFontName", NULL); if (s != "") { SysFreeString(_options.valuesFontName); _options.valuesFontName = A2BSTR(s); } - - s = CPLGetXMLValue( node, "ValuesFontSize", NULL ); - _options.valuesFontSize = (s != "") ? atoi(s.GetString()) : opt.valuesFontSize; - - s = CPLGetXMLValue( node, "ValuesFrameColor", NULL ); - _options.valuesFrameColor = (s != "") ? (OLE_COLOR)atoi(s.GetString()) : opt.valuesFrameColor; - - s = CPLGetXMLValue( node, "ValuesFrameVisible", NULL ); - _options.valuesFrameVisible = (s != "") ? (VARIANT_BOOL)atoi(s.GetString()) : opt.valuesFrameVisible; - s = CPLGetXMLValue( node, "ValuesStyle", NULL ); - _options.valuesStyle = (s != "") ? (tkChartValuesStyle)atoi(s.GetString()) : opt.valuesStyle; + s = CPLGetXMLValue(node, "ValuesFontSize", NULL); + _options.valuesFontSize = (s != "") ? atoi(s.GetString()) : opt.valuesFontSize; + + s = CPLGetXMLValue(node, "ValuesFrameColor", NULL); + _options.valuesFrameColor = (s != "") ? (OLE_COLOR)atoi(s.GetString()) : opt.valuesFrameColor; + + s = CPLGetXMLValue(node, "ValuesFrameVisible", NULL); + _options.valuesFrameVisible = (s != "") ? (VARIANT_BOOL)atoi(s.GetString()) : opt.valuesFrameVisible; - s = CPLGetXMLValue( node, "ValuesVisible", NULL ); - _options.valuesVisible = (s != "") ? (VARIANT_BOOL)atoi(s.GetString()) : opt.valuesVisible; + s = CPLGetXMLValue(node, "ValuesStyle", NULL); + _options.valuesStyle = (s != "") ? (tkChartValuesStyle)atoi(s.GetString()) : opt.valuesStyle; - s = CPLGetXMLValue( node, "VerticalPosition", NULL ); - _options.verticalPosition = (s != "") ? (tkVerticalPosition)atoi(s.GetString()) : opt.verticalPosition; + s = CPLGetXMLValue(node, "ValuesVisible", NULL); + _options.valuesVisible = (s != "") ? (VARIANT_BOOL)atoi(s.GetString()) : opt.valuesVisible; - s = CPLGetXMLValue( node, "Visible", NULL ); - _options.visible = (s != "") ? (VARIANT_BOOL)atoi(s.GetString()) : opt.visible; + s = CPLGetXMLValue(node, "VerticalPosition", NULL); + _options.verticalPosition = (s != "") ? (tkVerticalPosition)atoi(s.GetString()) : opt.verticalPosition; - s = CPLGetXMLValue( node, "SavingMode", NULL ); - _savingMode = (s != "") ? (tkSavingMode)atoi(s.GetString()) : modeXML; + s = CPLGetXMLValue(node, "Visible", NULL); + _options.visible = (s != "") ? (VARIANT_BOOL)atoi(s.GetString()) : opt.visible; + + s = CPLGetXMLValue(node, "SavingMode", NULL); + _savingMode = (s != "") ? (tkSavingMode)atoi(s.GetString()) : modeXML; return true; } @@ -1670,7 +1669,7 @@ bool CCharts::DeserializeCore(CPLXMLNode* node) STDMETHODIMP CCharts::Deserialize(BSTR newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - USES_CONVERSION; + USES_CONVERSION; CString s = OLE2CA(newVal); CPLXMLNode* node = CPLParseXMLString(s.GetString()); @@ -1692,7 +1691,7 @@ STDMETHODIMP CCharts::Deserialize(BSTR newVal) STDMETHODIMP CCharts::SaveToXML(BSTR Filename, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = VARIANT_FALSE; + *retVal = VARIANT_FALSE; USES_CONVERSION; CStringW s = OLE2W(Filename); @@ -1707,8 +1706,8 @@ STDMETHODIMP CCharts::SaveToXML(BSTR Filename, VARIANT_BOOL* retVal) ErrorMessage(tkINVALID_FILENAME); return S_OK; } - - CPLXMLNode *psTree = CPLCreateXMLNode( NULL, CXT_Element, "MapWindow" ); + + CPLXMLNode *psTree = CPLCreateXMLNode(NULL, CXT_Element, "MapWindow"); if (psTree) { Utility::WriteXmlHeaderAttributes(psTree, "Charts"); @@ -1732,12 +1731,12 @@ STDMETHODIMP CCharts::SaveToXML(BSTR Filename, VARIANT_BOOL* retVal) // ******************************************************** CPLXMLNode* CCharts::SerializeChartData(CString ElementName) { - CPLXMLNode* psCharts = CPLCreateXMLNode( NULL, CXT_Element, ElementName ); + CPLXMLNode* psCharts = CPLCreateXMLNode(NULL, CXT_Element, ElementName); if (psCharts) { if (!_shapefile) return NULL; - + std::vector* data = ((CShapefile*)_shapefile)->get_ShapeVector(); if (data) { @@ -1756,7 +1755,7 @@ CPLXMLNode* CCharts::SerializeChartData(CString ElementName) CPLAddXMLSibling(nodeOld, nodeNew); nodeOld = nodeNew; } - + CChartInfo* info = (*data)[i]->chart; Utility::CPLCreateXMLAttributeAndValue(nodeOld, "X", CPLString().Printf("%f", info->x)); Utility::CPLCreateXMLAttributeAndValue(nodeOld, "Y", CPLString().Printf("%f", info->y)); @@ -1772,7 +1771,7 @@ CPLXMLNode* CCharts::SerializeChartData(CString ElementName) STDMETHODIMP CCharts::get_SavingMode(tkSavingMode* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = _savingMode; + *retVal = _savingMode; return S_OK; } @@ -1782,7 +1781,7 @@ STDMETHODIMP CCharts::get_SavingMode(tkSavingMode* retVal) STDMETHODIMP CCharts::put_SavingMode(tkSavingMode newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - _savingMode = newVal; + _savingMode = newVal; return S_OK; } @@ -1792,8 +1791,8 @@ STDMETHODIMP CCharts::put_SavingMode(tkSavingMode newVal) STDMETHODIMP CCharts::LoadFromXML(BSTR Filename, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - *retVal = VARIANT_FALSE; - + *retVal = VARIANT_FALSE; + USES_CONVERSION; CStringW name = OLE2W(Filename); if (!Utility::FileExistsW(name)) @@ -1802,13 +1801,13 @@ STDMETHODIMP CCharts::LoadFromXML(BSTR Filename, VARIANT_BOOL* retVal) return S_OK; } - CPLXMLNode* node = GdalHelper::ParseXMLFile(name); + CPLXMLNode* node = GdalHelper::ParseXMLFile(name); if (node) { node = CPLGetXMLNode(node, "=MapWindow"); if (node) { - CString s = CPLGetXMLValue( node, "FileVersion", "0" ); + CString s = CPLGetXMLValue(node, "FileVersion", "0"); int version = atoi(s); node = CPLGetXMLNode(node, "Charts"); @@ -1828,40 +1827,38 @@ bool CCharts::DeserializeChartData(CPLXMLNode* node) { if (!node || !_shapefile) return false; - - CSingleLock sfLock(&((CShapefile*)_shapefile)->ShapefileLock, TRUE); - + std::vector* data = ((CShapefile*)_shapefile)->get_ShapeVector(); if (!data) return false; - this->Clear(); - ((CShapefile*)_shapefile)->SetChartsPositions(lpNone); + this->Clear(); + ((CShapefile*)_shapefile)->SetChartsPositions(lpNone); - CString s; - double x, y; - int i = 0; + CString s; + double x, y; + int i = 0; - node = CPLGetXMLNode(node, "Chart"); + node = CPLGetXMLNode(node, "Chart"); - int count = data->size(); - while (node && i < count) - { - s = CPLGetXMLValue(node, "X", "0.0"); - x = Utility::atof_custom(s); + int count = data->size(); + while (node && i < count) + { + s = CPLGetXMLValue(node, "X", "0.0"); + x = Utility::atof_custom(s); - s = CPLGetXMLValue(node, "Y", "0.0"); - y = Utility::atof_custom(s); + s = CPLGetXMLValue(node, "Y", "0.0"); + y = Utility::atof_custom(s); - CChartInfo* info = (*data)[i]->chart; - info->x = x; - info->y = y; - i++; + CChartInfo* info = (*data)[i]->chart; + info->x = x; + info->y = y; + i++; - node = node->psNext; - } - _chartsExist = true; - return true; + node = node->psNext; + } + _chartsExist = true; + return true; } #pragma endregion \ No newline at end of file diff --git a/src/COM classes/FieldStatOperations.cpp b/src/COM classes/FieldStatOperations.cpp index 67033153..e66f8cdb 100644 --- a/src/COM classes/FieldStatOperations.cpp +++ b/src/COM classes/FieldStatOperations.cpp @@ -1,7 +1,6 @@ // FieldStatOperations.cpp : Implementation of CFieldStatOperations #include "stdafx.h" -#include "Shapefile.h" #include "FieldStatOperations.h" //*********************************************************************** @@ -191,7 +190,6 @@ STDMETHODIMP CFieldStatOperations::Validate(IShapefile* sf, VARIANT_BOOL* retVal } else { - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); long numFields; sf->get_NumFields(&numFields); diff --git a/src/COM classes/OgrDatasource.cpp b/src/COM classes/OgrDatasource.cpp index 6c0dbe3b..610f9aed 100644 --- a/src/COM classes/OgrDatasource.cpp +++ b/src/COM classes/OgrDatasource.cpp @@ -405,8 +405,6 @@ STDMETHODIMP COgrDatasource::ImportShapefile(IShapefile* shapefile, BSTR newLaye return S_OK; } - CSingleLock sfLock(&((CShapefile*) shapefile)->ShapefileLock, TRUE); - CStringA name = OgrHelper::Bstr2OgrString(newLayerName); if (name.GetLength() == 0) { diff --git a/src/COM classes/OgrLayer.cpp b/src/COM classes/OgrLayer.cpp index ad346dbd..dd0a9741 100644 --- a/src/COM classes/OgrLayer.cpp +++ b/src/COM classes/OgrLayer.cpp @@ -19,8 +19,8 @@ // InjectShapefile() // ************************************************************* void COgrLayer::InjectShapefile(IShapefile* sfNew) -{ - CSingleLock lock(&_loader.ProviderLock, TRUE); +{ // Lock shape file + CSingleLock sfLock(&_loader.ShapefileLock, _dynamicLoading ? TRUE : FALSE); CloseShapefile(); _shapefile = sfNew; } @@ -30,7 +30,6 @@ void COgrLayer::InjectShapefile(IShapefile* sfNew) // ************************************************************* void COgrLayer::InitOpenedLayer() { - CSingleLock lock(&_loader.ProviderLock, TRUE); if (Utility::FileExistsW(_connectionString)) { _sourceType = ogrFile; } @@ -61,7 +60,6 @@ void COgrLayer::InitOpenedLayer() //*********************************************************************** void COgrLayer::ClearCachedValues() { - CSingleLock lock(&_loader.ProviderLock, TRUE); if (_envelope) { delete _envelope; @@ -79,7 +77,7 @@ void COgrLayer::ClearCachedValues() void COgrLayer::StopBackgroundLoading() { _loader.CancelAllTasks(); // notify working thread that it's time is over - CSingleLock lock(&_loader.LoadingLock, TRUE); + CSingleLock lock(&_loader.LoadingLock, _dynamicLoading ? TRUE : FALSE); } //*********************************************************************** @@ -87,10 +85,6 @@ void COgrLayer::StopBackgroundLoading() //*********************************************************************** IShapefile* COgrLayer::LoadShapefile() { - // Lock it all down: - CSingleLock ldLock(&_loader.LoadingLock, TRUE); - CSingleLock prLock(&_loader.ProviderLock, TRUE); - bool isTrimmed = false; IShapefile* sf = Ogr2Shape::Layer2Shapefile(_layer, _activeShapeType, _loader.GetMaxCacheCount(), isTrimmed, &_loader, _globalCallback); if (isTrimmed) { @@ -113,7 +107,7 @@ void COgrLayer::UpdateShapefileFromOGRLoader() // Lock it all down: CSingleLock ldLock(&_loader.LoadingLock, TRUE); CSingleLock prLock(&_loader.ProviderLock, TRUE); - CSingleLock sfLock(&((CShapefile*) _shapefile)->ShapefileLock, TRUE); + CSingleLock sfLock(&_loader.ShapefileLock, TRUE); // Grab the loaded data: vector data = _loader.FetchData(); @@ -180,16 +174,14 @@ STDMETHODIMP COgrLayer::get_Key(BSTR *pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) USES_CONVERSION; - CSingleLock lock(&_loader.ProviderLock, TRUE); *pVal = OLE2BSTR(_key); return S_OK; } STDMETHODIMP COgrLayer::put_Key(BSTR newVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + ::SysFreeString(_key); USES_CONVERSION; - CSingleLock lock(&_loader.ProviderLock, TRUE); - ::SysFreeString(_key); _key = OLE2BSTR(newVal); return S_OK; } @@ -199,15 +191,13 @@ STDMETHODIMP COgrLayer::put_Key(BSTR newVal) //***********************************************************************/ void COgrLayer::ErrorMessage(long ErrorCode) { - CSingleLock lock(&_loader.ProviderLock, TRUE); _lastErrorCode = ErrorCode; CallbackHelper::ErrorMsg("OgrLayer", _globalCallback, _key, ErrorMsg(_lastErrorCode)); } STDMETHODIMP COgrLayer::get_LastErrorCode(long *pVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) *pVal = _lastErrorCode; _lastErrorCode = tkNO_ERROR; return S_OK; @@ -215,8 +205,7 @@ STDMETHODIMP COgrLayer::get_LastErrorCode(long *pVal) STDMETHODIMP COgrLayer::get_ErrorMsg(long ErrorCode, BSTR *pVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) USES_CONVERSION; *pVal = A2BSTR(ErrorMsg(ErrorCode)); return S_OK; @@ -227,8 +216,7 @@ STDMETHODIMP COgrLayer::get_ErrorMsg(long ErrorCode, BSTR *pVal) //***********************************************************************/ STDMETHODIMP COgrLayer::get_GlobalCallback(ICallback **pVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) *pVal = _globalCallback; if (_globalCallback != NULL) _globalCallback->AddRef(); return S_OK; @@ -236,8 +224,7 @@ STDMETHODIMP COgrLayer::get_GlobalCallback(ICallback **pVal) STDMETHODIMP COgrLayer::put_GlobalCallback(ICallback *newVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) ComHelper::SetRef(newVal, (IDispatch**)&_globalCallback); return S_OK; } @@ -247,7 +234,6 @@ STDMETHODIMP COgrLayer::put_GlobalCallback(ICallback *newVal) // ************************************************************* bool COgrLayer::CheckState() { - CSingleLock lock(&_loader.ProviderLock, TRUE); if (!_dataset) { ErrorMessage(tkOGR_LAYER_UNINITIALIZED); @@ -262,7 +248,6 @@ bool COgrLayer::CheckState() STDMETHODIMP COgrLayer::get_SourceType(tkOgrSourceType* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = _sourceType; return S_OK; } @@ -272,8 +257,7 @@ STDMETHODIMP COgrLayer::get_SourceType(tkOgrSourceType* retVal) // ************************************************************* STDMETHODIMP COgrLayer::Close() { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) StopBackgroundLoading(); @@ -315,8 +299,8 @@ STDMETHODIMP COgrLayer::Close() // CloseShapefile() // ************************************************************* void COgrLayer::CloseShapefile() -{ - CSingleLock lock(&_loader.ProviderLock, TRUE); +{ // Lock shape file + CSingleLock sfLock(&_loader.ShapefileLock, _dynamicLoading ? TRUE : FALSE); if (_shapefile) { VARIANT_BOOL vb; @@ -331,7 +315,6 @@ void COgrLayer::CloseShapefile() // ************************************************************* GDALDataset* COgrLayer::OpenDataset(BSTR connectionString, bool forUpdate) { - CSingleLock lock(&_loader.ProviderLock, TRUE); GDALDataset* ds = GdalHelper::OpenOgrDatasetW(OLE2W(connectionString), forUpdate, true); if (!ds) { @@ -347,7 +330,6 @@ GDALDataset* COgrLayer::OpenDataset(BSTR connectionString, bool forUpdate) STDMETHODIMP COgrLayer::OpenDatabaseLayer(BSTR connectionString, int layerIndex, VARIANT_BOOL forUpdate, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = VARIANT_FALSE; GDALDataset* ds = OpenDataset(connectionString, forUpdate ? true : false); @@ -367,7 +349,6 @@ STDMETHODIMP COgrLayer::OpenDatabaseLayer(BSTR connectionString, int layerIndex, // ************************************************************* bool COgrLayer::OpenDatabaseLayerCore(GDALDataset* ds, CStringW connectionString, int layerIndex, VARIANT_BOOL forUpdate, VARIANT_BOOL externalDatasource) { - CSingleLock lock(&_loader.ProviderLock, TRUE); Close(); if (!ds) { @@ -406,7 +387,6 @@ bool COgrLayer::OpenDatabaseLayerCore(GDALDataset* ds, CStringW connectionString // ************************************************************* bool COgrLayer::InjectLayer(GDALDataset* ds, int layerIndex, CStringW connection, VARIANT_BOOL forUpdate) { - CSingleLock lock(&_loader.ProviderLock, TRUE); return OpenDatabaseLayerCore(ds, connection, layerIndex, forUpdate, VARIANT_TRUE); } @@ -416,8 +396,6 @@ bool COgrLayer::InjectLayer(GDALDataset* ds, int layerIndex, CStringW connection STDMETHODIMP COgrLayer::ExtendFromQuery(BSTR sql, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock ldLock(&_loader.LoadingLock, TRUE); - CSingleLock prLock(&_loader.ProviderLock, TRUE); *retVal = VARIANT_FALSE; @@ -446,9 +424,7 @@ STDMETHODIMP COgrLayer::ExtendFromQuery(BSTR sql, VARIANT_BOOL* retVal) // ************************************************************* STDMETHODIMP COgrLayer::OpenFromQuery(BSTR connectionString, BSTR sql, VARIANT_BOOL* retVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); - + AFX_MANAGE_STATE(AfxGetStaticModuleState()) *retVal = VARIANT_FALSE; Close(); @@ -482,9 +458,7 @@ STDMETHODIMP COgrLayer::OpenFromQuery(BSTR connectionString, BSTR sql, VARIANT_B // ************************************************************* STDMETHODIMP COgrLayer::OpenFromDatabase(BSTR connectionString, BSTR layerName, VARIANT_BOOL forUpdate, VARIANT_BOOL* retVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); - + AFX_MANAGE_STATE(AfxGetStaticModuleState()) *retVal = VARIANT_FALSE; Close(); @@ -519,7 +493,6 @@ STDMETHODIMP COgrLayer::OpenFromDatabase(BSTR connectionString, BSTR layerName, STDMETHODIMP COgrLayer::OpenFromFile(BSTR Filename, VARIANT_BOOL forUpdate, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = VARIANT_FALSE; Close(); @@ -554,8 +527,7 @@ STDMETHODIMP COgrLayer::OpenFromFile(BSTR Filename, VARIANT_BOOL forUpdate, VARI // ************************************************************* STDMETHODIMP COgrLayer::get_Name(BSTR* retVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) if (!CheckState()) { *retVal = A2BSTR(""); @@ -575,19 +547,23 @@ STDMETHODIMP COgrLayer::get_Name(BSTR* retVal) STDMETHODIMP COgrLayer::GetBuffer(IShapefile** retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = NULL; if (!CheckState()) return S_OK; // Lock shape file + CSingleLock sfLock(&_loader.ShapefileLock, _dynamicLoading ? TRUE : FALSE); if (!_shapefile) { if (_dynamicLoading) + { // Lock provider + CSingleLock lock(&_loader.ProviderLock, _dynamicLoading ? TRUE : FALSE); _shapefile = Ogr2Shape::CreateShapefile(_layer, _activeShapeType); - else + } + else { _shapefile = LoadShapefile(); } + } if (_shapefile) { @@ -603,7 +579,6 @@ STDMETHODIMP COgrLayer::GetBuffer(IShapefile** retVal) STDMETHODIMP COgrLayer::ReloadFromSource(VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = VARIANT_FALSE; if (!CheckState()) return S_OK; @@ -613,6 +588,8 @@ STDMETHODIMP COgrLayer::ReloadFromSource(VARIANT_BOOL* retVal) return S_OK; } + // Lock shape file + CSingleLock sfLock(&_loader.ShapefileLock, _dynamicLoading ? TRUE : FALSE); CloseShapefile(); _shapefile = LoadShapefile(); @@ -626,7 +603,6 @@ STDMETHODIMP COgrLayer::ReloadFromSource(VARIANT_BOOL* retVal) STDMETHODIMP COgrLayer::RedefineQuery(BSTR newSql, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = VARIANT_FALSE; if (!CheckState()) return S_OK; @@ -669,7 +645,6 @@ STDMETHODIMP COgrLayer::GetConnectionString(BSTR* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); USES_CONVERSION; - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = W2BSTR(_connectionString); return S_OK; } @@ -681,7 +656,6 @@ STDMETHODIMP COgrLayer::GetSourceQuery(BSTR* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); USES_CONVERSION; - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = W2BSTR(_sourceQuery); return S_OK; } @@ -692,14 +666,15 @@ STDMETHODIMP COgrLayer::GetSourceQuery(BSTR* retVal) STDMETHODIMP COgrLayer::get_GeoProjection(IGeoProjection** retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); - IGeoProjection* gp = NULL; ComHelper::CreateInstance(idGeoProjection, (IDispatch**)&gp); *retVal = gp; if (!CheckState()) return S_OK; + // Locking provider here + CSingleLock lock(&_loader.ProviderLock, _dynamicLoading ? TRUE: FALSE); + OGRSpatialReference* sr = _layer->GetSpatialRef(); // owned by OGRLayer if (sr) ((CGeoProjection*)gp)->InjectSpatialReference(sr); return S_OK; @@ -711,8 +686,6 @@ STDMETHODIMP COgrLayer::get_GeoProjection(IGeoProjection** retVal) STDMETHODIMP COgrLayer::get_ShapeType(ShpfileType* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); - *retVal = SHP_NULLSHAPE; if (!CheckState()) return S_OK; *retVal = OgrConverter::GeometryType2ShapeType(_layer->GetGeomType()); @@ -725,8 +698,6 @@ STDMETHODIMP COgrLayer::get_ShapeType(ShpfileType* retVal) STDMETHODIMP COgrLayer::get_ShapeType2D(ShpfileType* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); - get_ShapeType(pVal); *pVal = ShapeUtility::Convert2D(*pVal); return S_OK; @@ -738,8 +709,6 @@ STDMETHODIMP COgrLayer::get_ShapeType2D(ShpfileType* pVal) STDMETHODIMP COgrLayer::get_DataIsReprojected(VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); - *retVal = VARIANT_FALSE; if (!CheckState()) return S_OK; if (!_shapefile) return S_OK; // data wasn't loaded yet @@ -767,8 +736,6 @@ STDMETHODIMP COgrLayer::get_DataIsReprojected(VARIANT_BOOL* retVal) STDMETHODIMP COgrLayer::get_FIDColumnName(BSTR* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); - if (CheckState()) { CStringW s = OgrHelper::OgrString2Unicode(_layer->GetFIDColumn()); @@ -785,8 +752,6 @@ STDMETHODIMP COgrLayer::get_FIDColumnName(BSTR* retVal) STDMETHODIMP COgrLayer::SaveChanges(int* savedCount, tkOgrSaveType saveType, VARIANT_BOOL validateShapes, tkOgrSaveResult* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); - *savedCount = 0; *retVal = osrNoChanges; _updateErrors.clear(); @@ -823,7 +788,8 @@ STDMETHODIMP COgrLayer::SaveChanges(int* savedCount, tkOgrSaveType saveType, VAR } { // Locking provider & shapefile here - CSingleLock lock(&_loader.ProviderLock, TRUE); + CSingleLock lock(&_loader.ProviderLock, _dynamicLoading ? TRUE : FALSE); + CSingleLock sfLock(&_loader.ShapefileLock, _dynamicLoading ? TRUE : FALSE); *savedCount = Shape2Ogr::SaveShapefileChanges(_layer, _shapefile, shapeCmnId, saveType, validateShapes ? true : false, _updateErrors); } @@ -844,15 +810,14 @@ STDMETHODIMP COgrLayer::SaveChanges(int* savedCount, tkOgrSaveType saveType, VAR STDMETHODIMP COgrLayer::HasLocalChanges(VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = VARIANT_FALSE; if (!CheckState() || !_shapefile) return S_OK; { // Locking provider & shapefile here - CSingleLock lock(&_loader.ProviderLock, TRUE); - CSingleLock sfLock(&((CShapefile*)_shapefile)->ShapefileLock, TRUE); + CSingleLock lock(&_loader.ProviderLock, _dynamicLoading ? TRUE : FALSE); + CSingleLock sfLock(&_loader.ShapefileLock, _dynamicLoading ? TRUE : FALSE); long numShapes; _shapefile->get_NumShapes(&numShapes); @@ -918,7 +883,7 @@ long COgrLayer::GetFidForShapefile() { if (!_layer || !_shapefile) return -1; // Locking shapefile here - CSingleLock sfLock(&((CShapefile*)_shapefile)->ShapefileLock, TRUE); + CSingleLock sfLock(&_loader.ShapefileLock, _dynamicLoading ? TRUE : FALSE); CComBSTR bstr; get_FIDColumnName(&bstr); CComPtr table = NULL; @@ -934,8 +899,6 @@ long COgrLayer::GetFidForShapefile() STDMETHODIMP COgrLayer::TestCapability(tkOgrLayerCapability capability, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock lock(&_loader.ProviderLock, TRUE); - *retVal = VARIANT_FALSE; if (!CheckState()) return S_OK; int val = _layer->TestCapability(OgrHelper::GetLayerCapabilityString(capability)); @@ -949,8 +912,6 @@ STDMETHODIMP COgrLayer::TestCapability(tkOgrLayerCapability capability, VARIANT_ STDMETHODIMP COgrLayer::get_UpdateSourceErrorCount(int* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock lock(&_loader.ProviderLock, TRUE); - *retVal = _updateErrors.size(); return S_OK; } @@ -961,8 +922,6 @@ STDMETHODIMP COgrLayer::get_UpdateSourceErrorCount(int* retVal) STDMETHODIMP COgrLayer::get_UpdateSourceErrorMsg(int errorIndex, BSTR* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock lock(&_loader.ProviderLock, TRUE); - if (errorIndex < 0 || errorIndex >= (int)_updateErrors.size()) { *retVal = A2BSTR(""); @@ -979,8 +938,6 @@ STDMETHODIMP COgrLayer::get_UpdateSourceErrorMsg(int errorIndex, BSTR* retVal) STDMETHODIMP COgrLayer::get_UpdateSourceErrorShapeIndex(int errorIndex, int* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock lock(&_loader.ProviderLock, TRUE); - if (errorIndex < 0 || errorIndex >= (int)_updateErrors.size()) { *retVal = -1; @@ -997,11 +954,13 @@ STDMETHODIMP COgrLayer::get_UpdateSourceErrorShapeIndex(int errorIndex, int* ret STDMETHODIMP COgrLayer::get_FeatureCount(VARIANT_BOOL forceLoading, int* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = 0; if (!CheckState()) return S_OK; + { // Locking provider here + CSingleLock lock(&_loader.ProviderLock, _dynamicLoading ? TRUE : FALSE); + if (_featureCount == -1 || forceLoading) { _featureCount = static_cast(_layer->GetFeatureCount(forceLoading == VARIANT_TRUE)); @@ -1009,6 +968,7 @@ STDMETHODIMP COgrLayer::get_FeatureCount(VARIANT_BOOL forceLoading, int* retVal) *retVal = _featureCount; return S_OK; } +} // ************************************************************* @@ -1016,13 +976,16 @@ STDMETHODIMP COgrLayer::get_FeatureCount(VARIANT_BOOL forceLoading, int* retVal) // ************************************************************* void COgrLayer::ForceCreateShapefile() { - CSingleLock lock(&_loader.ProviderLock, TRUE); tkOgrSourceType sourceType; get_SourceType(&sourceType); if (_dynamicLoading && !_shapefile && sourceType != ogrUninitialized) + { // Lock the provider & shapefile + CSingleLock lock(&_loader.ProviderLock, _dynamicLoading ? TRUE : FALSE); + CSingleLock sfLock(&_loader.ShapefileLock, _dynamicLoading ? TRUE : FALSE); _shapefile = Ogr2Shape::CreateShapefile(_layer, _activeShapeType); } +} // ************************************************************* // get_Extents() @@ -1030,7 +993,6 @@ void COgrLayer::ForceCreateShapefile() STDMETHODIMP COgrLayer::get_Extents(IExtents** extents, VARIANT_BOOL forceLoading, VARIANT_BOOL *retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock lock(&_loader.ProviderLock, TRUE); *extents = NULL; *retVal = VARIANT_FALSE; if (!CheckState()) return S_OK; @@ -1041,7 +1003,8 @@ STDMETHODIMP COgrLayer::get_Extents(IExtents** extents, VARIANT_BOOL forceLoadin } if (!_envelope) - { + { // Locking provider here + CSingleLock lock(&_loader.ProviderLock, _dynamicLoading ? TRUE : FALSE); _envelope = new OGREnvelope(); _layer->GetExtent(_envelope, forceLoading == VARIANT_TRUE); } @@ -1063,8 +1026,7 @@ STDMETHODIMP COgrLayer::get_Extents(IExtents** extents, VARIANT_BOOL forceLoadin // ************************************************************* STDMETHODIMP COgrLayer::get_GeometryColumnName(BSTR* retVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) if (!CheckState()) return S_OK; CStringW name = OgrHelper::OgrString2Unicode(_layer->GetGeometryColumn()); USES_CONVERSION; @@ -1077,10 +1039,9 @@ STDMETHODIMP COgrLayer::get_GeometryColumnName(BSTR* retVal) // ************************************************************* STDMETHODIMP COgrLayer::get_SupportsEditing(tkOgrSaveType editingType, VARIANT_BOOL* retVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) *retVal = VARIANT_FALSE; - if (!CheckState() || !_shapefile) return S_OK; + if (!CheckState()) return S_OK; // is it supported by driver? VARIANT_BOOL randomWrite; @@ -1093,7 +1054,7 @@ STDMETHODIMP COgrLayer::get_SupportsEditing(tkOgrSaveType editingType, VARIANT_B // do we have FID column? { // Locking shapefile here - CSingleLock sfLock(&((CShapefile*)_shapefile)->ShapefileLock, TRUE); + CSingleLock sfLock(&_loader.ShapefileLock, _dynamicLoading ? TRUE : FALSE); if (_shapefile) { long fid = GetFidForShapefile(); @@ -1132,8 +1093,7 @@ STDMETHODIMP COgrLayer::get_SupportsEditing(tkOgrSaveType editingType, VARIANT_B // ************************************************************* STDMETHODIMP COgrLayer::Serialize(BSTR* retVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) CPLXMLNode* psTree = this->SerializeCore("OgrLayerClass"); Utility::SerializeAndDestroyXmlTree(psTree, retVal); return S_OK; @@ -1144,7 +1104,6 @@ STDMETHODIMP COgrLayer::Serialize(BSTR* retVal) // ************************************************************* CPLXMLNode* COgrLayer::SerializeCore(CString ElementName) { - CSingleLock lock(&_loader.ProviderLock, TRUE); CPLXMLNode* psTree = CPLCreateXMLNode(NULL, CXT_Element, ElementName); USES_CONVERSION; @@ -1163,11 +1122,14 @@ CPLXMLNode* COgrLayer::SerializeCore(CString ElementName) if (_loader.GetMaxCacheCount() != m_globalSettings.ogrLayerMaxFeatureCount) Utility::CPLCreateXMLAttributeAndValue(psTree, "MaxFeatureCount", CPLString().Printf("%d", (int)_loader.GetMaxCacheCount())); + { // Lock shape file + CSingleLock lock(&_loader.ProviderLock, _dynamicLoading ? TRUE : FALSE); if (_shapefile) { CPLXMLNode* sfNode = ((CShapefile*)_shapefile)->SerializeCore(VARIANT_FALSE, "ShapefileData", true); CPLAddXMLChild(psTree, sfNode); } + } return psTree; } @@ -1176,8 +1138,7 @@ CPLXMLNode* COgrLayer::SerializeCore(CString ElementName) // ************************************************************* STDMETHODIMP COgrLayer::Deserialize(BSTR newVal, VARIANT_BOOL* retVal) { - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); + AFX_MANAGE_STATE(AfxGetStaticModuleState()) *retVal = VARIANT_FALSE; USES_CONVERSION; @@ -1201,7 +1162,6 @@ STDMETHODIMP COgrLayer::Deserialize(BSTR newVal, VARIANT_BOOL* retVal) // ************************************************************* bool COgrLayer::DeserializeCore(CPLXMLNode* node) { - CSingleLock lock(&_loader.ProviderLock, TRUE); if (!node) return false; Close(); @@ -1238,7 +1198,6 @@ bool COgrLayer::DeserializeCore(CPLXMLNode* node) // ************************************************************* bool COgrLayer::DeserializeOptions(CPLXMLNode* node) { - CSingleLock lock(&_loader.ProviderLock, TRUE); bool success = true; _loader.LabelExpression = Utility::ConvertFromUtf8(CPLGetXMLValue(node, "LabelExpression", "")); @@ -1257,14 +1216,14 @@ bool COgrLayer::DeserializeOptions(CPLXMLNode* node) CPLXMLNode* psChild = CPLGetXMLNode(node, "ShapefileData"); if (psChild) { // Lock shape file + CSingleLock sfLock(&_loader.ShapefileLock, _dynamicLoading ? TRUE : FALSE); if (!_shapefile) { IShapefile * sf = LoadShapefile(); _shapefile = sf; } - CSingleLock sfLock(&((CShapefile*)_shapefile)->ShapefileLock, TRUE); bool result = ((CShapefile*)_shapefile)->DeserializeCore(VARIANT_FALSE, psChild); if (!result) success = false; - } + } } CString key = CPLGetXMLValue(node, "Key", ""); @@ -1282,7 +1241,6 @@ bool COgrLayer::DeserializeOptions(CPLXMLNode* node) STDMETHODIMP COgrLayer::get_GdalLastErrorMsg(BSTR* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); CStringW s = OgrHelper::OgrString2Unicode(CPLGetLastErrorMsg()); *pVal = W2BSTR(s); return S_OK; @@ -1300,7 +1258,6 @@ STDMETHODIMP COgrLayer::get_DynamicLoading(VARIANT_BOOL* pVal) STDMETHODIMP COgrLayer::put_DynamicLoading(VARIANT_BOOL newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); _dynamicLoading = newVal; if (newVal) { ForceCreateShapefile(); @@ -1314,14 +1271,12 @@ STDMETHODIMP COgrLayer::put_DynamicLoading(VARIANT_BOOL newVal) STDMETHODIMP COgrLayer::get_MaxFeatureCount(LONG* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *pVal = _loader.GetMaxCacheCount(); return S_OK; } STDMETHODIMP COgrLayer::put_MaxFeatureCount(LONG newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); _loader.SetMaxCacheCount(newVal <= 0 ? m_globalSettings.ogrLayerMaxFeatureCount : newVal); return S_OK; } @@ -1332,7 +1287,6 @@ STDMETHODIMP COgrLayer::put_MaxFeatureCount(LONG newVal) bool COgrLayer::HasStyleTable() { if (!CheckState()) return false; - CSingleLock lock(&_loader.ProviderLock, TRUE); return OgrStyleHelper::HasStyleTable(_dataset, GetLayerName()); } @@ -1341,7 +1295,6 @@ bool COgrLayer::HasStyleTable() // ************************************************************* CStringW COgrLayer::GetLayerName() { - CSingleLock lock(&_loader.ProviderLock, TRUE); return OgrHelper::OgrString2Unicode(_layer->GetName()); } @@ -1350,7 +1303,6 @@ CStringW COgrLayer::GetLayerName() // ************************************************************* CStringW COgrLayer::GetStyleTableName() { - CSingleLock lock(&_loader.ProviderLock, TRUE); return OgrStyleHelper::GetStyleTableName(GetLayerName()); } @@ -1360,7 +1312,6 @@ CStringW COgrLayer::GetStyleTableName() STDMETHODIMP COgrLayer::get_SupportsStyles(VARIANT_BOOL* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *pVal = VARIANT_FALSE; if (!CheckState()) return S_OK; @@ -1386,7 +1337,6 @@ STDMETHODIMP COgrLayer::get_SupportsStyles(VARIANT_BOOL* pVal) STDMETHODIMP COgrLayer::SaveStyle(BSTR Name, CStringW xml, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = VARIANT_FALSE; if (!CheckState()) return S_OK; @@ -1417,7 +1367,6 @@ STDMETHODIMP COgrLayer::SaveStyle(BSTR Name, CStringW xml, VARIANT_BOOL* retVal) STDMETHODIMP COgrLayer::GetNumStyles(LONG* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *pVal = -1; if (!CheckState()) return S_OK; @@ -1445,7 +1394,6 @@ STDMETHODIMP COgrLayer::GetNumStyles(LONG* pVal) STDMETHODIMP COgrLayer::get_StyleName(LONG styleIndex, BSTR* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); if (!CheckState()) return S_OK; @@ -1484,8 +1432,8 @@ STDMETHODIMP COgrLayer::get_StyleName(LONG styleIndex, BSTR* pVal) // ************************************************************* CStringW COgrLayer::LoadStyleXML(CStringW name) { - CSingleLock lock(&_loader.ProviderLock, TRUE); if (!CheckState()) return L""; + CSingleLock lock(&_loader.ProviderLock, _dynamicLoading ? TRUE : FALSE); return OgrStyleHelper::LoadStyle(_dataset, GetStyleTableName(), GetLayerName(), name); } @@ -1495,7 +1443,6 @@ CStringW COgrLayer::LoadStyleXML(CStringW name) STDMETHODIMP COgrLayer::ClearStyles(VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); if (!CheckState() || !HasStyleTable()) { @@ -1520,7 +1467,6 @@ STDMETHODIMP COgrLayer::ClearStyles(VARIANT_BOOL* retVal) STDMETHODIMP COgrLayer::RemoveStyle(BSTR styleName, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = VARIANT_FALSE; if (!CheckState()) return S_OK; @@ -1538,7 +1484,6 @@ STDMETHODIMP COgrLayer::get_LabelExpression(BSTR* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); USES_CONVERSION; - CSingleLock lock(&_loader.ProviderLock, TRUE); *pVal = W2BSTR(_loader.LabelExpression); return S_OK; } @@ -1546,7 +1491,6 @@ STDMETHODIMP COgrLayer::put_LabelExpression(BSTR newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); USES_CONVERSION; - CSingleLock lock(&_loader.ProviderLock, TRUE); _loader.LabelExpression = OLE2W(newVal); return S_OK; } @@ -1557,14 +1501,12 @@ STDMETHODIMP COgrLayer::put_LabelExpression(BSTR newVal) STDMETHODIMP COgrLayer::get_LabelPosition(tkLabelPositioning* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *pVal = _loader.LabelPosition; return S_OK; } STDMETHODIMP COgrLayer::put_LabelPosition(tkLabelPositioning newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); _loader.LabelPosition = newVal; return S_OK; } @@ -1575,14 +1517,12 @@ STDMETHODIMP COgrLayer::put_LabelPosition(tkLabelPositioning newVal) STDMETHODIMP COgrLayer::get_LabelOrientation(tkLineLabelOrientation* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *pVal = _loader.LabelOrientation; return S_OK; } STDMETHODIMP COgrLayer::put_LabelOrientation(tkLineLabelOrientation newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); _loader.LabelOrientation = newVal; return S_OK; } @@ -1592,7 +1532,6 @@ STDMETHODIMP COgrLayer::put_LabelOrientation(tkLineLabelOrientation newVal) // ************************************************************* void COgrLayer::GetFieldValues(OGRFieldType fieldType, BSTR& fieldName, vector& values) { - CSingleLock lock(&_loader.ProviderLock, TRUE); if (_sourceType == ogrDbTable || _sourceType == ogrFile) { // load only the necessary column @@ -1620,7 +1559,6 @@ STDMETHODIMP COgrLayer::GenerateCategories(BSTR FieldName, tkClassificationType tkColorSchemeType schemeType, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *retVal = VARIANT_FALSE; if (!CheckState()) return S_OK; @@ -1702,7 +1640,6 @@ STDMETHODIMP COgrLayer::GenerateCategories(BSTR FieldName, tkClassificationType STDMETHODIMP COgrLayer::get_DriverName(BSTR* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); if (!CheckState()) { *pVal = A2BSTR(""); @@ -1722,7 +1659,6 @@ STDMETHODIMP COgrLayer::get_DriverName(BSTR* pVal) STDMETHODIMP COgrLayer::get_AvailableShapeTypes(VARIANT* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); vector result; if (!CheckState()) @@ -1778,7 +1714,6 @@ STDMETHODIMP COgrLayer::get_AvailableShapeTypes(VARIANT* pVal) // ************************************************************* void COgrLayer::GetMsSqlShapeTypes(vector& result) { - CSingleLock lock(&_loader.ProviderLock, TRUE); CStringW cmnName = Utility::ConvertFromUtf8(_layer->GetGeometryColumn()); CStringW layerName = Utility::ConvertFromUtf8(_layer->GetName()); CStringW sql; @@ -1823,7 +1758,6 @@ void COgrLayer::GetMsSqlShapeTypes(vector& result) STDMETHODIMP COgrLayer::get_ActiveShapeType(ShpfileType* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); ShpfileType shpType; get_ShapeType(&shpType); @@ -1836,7 +1770,6 @@ STDMETHODIMP COgrLayer::get_ActiveShapeType(ShpfileType* pVal) STDMETHODIMP COgrLayer::put_ActiveShapeType(ShpfileType newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); ShpfileType shpType; get_ShapeType(&shpType); @@ -1867,7 +1800,6 @@ STDMETHODIMP COgrLayer::put_ActiveShapeType(ShpfileType newVal) STDMETHODIMP COgrLayer::get_IsExternalDatasource(VARIANT_BOOL* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock lock(&_loader.ProviderLock, TRUE); *pVal = _externalDatasource; diff --git a/src/COM classes/ShapeEditor.cpp b/src/COM classes/ShapeEditor.cpp index 780d5db3..98a4b13c 100644 --- a/src/COM classes/ShapeEditor.cpp +++ b/src/COM classes/ShapeEditor.cpp @@ -1211,17 +1211,17 @@ bool CShapeEditor::TrySaveShape(IShape* shp) } VARIANT_BOOL vb; - long shapeIndex = _shapeIndex; - long layerHandle = _layerHandle; + int shapeIndex = _shapeIndex; + int layerHandle = _layerHandle; bool newShape = _shapeIndex == -1; if (newShape) { - long newIndex; - sf->EditAddShape(shp, &newIndex); + long numShapes = ShapefileHelper::GetNumShapes(sf); IUndoList* undoList = _mapCallback->_GetUndoList(); - undoList->Add(uoAddShape, (long)_layerHandle, newIndex, &vb); - shapeIndex = newIndex; + undoList->Add(uoAddShape, (long)_layerHandle, (long)numShapes, &vb); + sf->EditInsertShape(shp, &numShapes, &vb); + shapeIndex = numShapes; } else { diff --git a/src/COM classes/Shapefile.cpp b/src/COM classes/Shapefile.cpp index f0d22a53..9f6eee27 100644 --- a/src/COM classes/Shapefile.cpp +++ b/src/COM classes/Shapefile.cpp @@ -1,3594 +1,3489 @@ -//******************************************************************************************************** -//File name: Shapefile.cpp -//Description: Implementation of the CShapefile -//******************************************************************************************************** -//The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -//you may not use this file except in compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -//ANY KIND, either express or implied. See the License for the specific language governing rights and -//limitations under the License. -// -//The Original Code is MapWindow Open Source. -// -//The Initial Developer of this version of the Original Code is Daniel P. Ames using portions created by -//Utah State University and the Idaho National Engineering and Environmental Lab that were released as -//public domain in March 2004. -//******************************************************************************************************** -// -//Contributor(s): (Open source contributors should list themselves and their modifications here). -// ------------------------------------------------------------------------------------------------------- -// Paul Meems August 2018: Modernized the code as suggested by CLang and ReSharper - -#include "StdAfx.h" -#include -#include "Shapefile.h" -#include "Labels.h" -#include "Charts.h" -#include "GeoProjection.h" -#include "Templates.h" -#include -#include "ShapefileCategories.h" -#include "Shape.h" -#include "GeosConverter.h" -#include "ShapefileHelper.h" -#include "LabelsHelper.h" -#include "ShapeStyleHelper.h" -#include "TableClass.h" - -#ifdef _DEBUG - #define new DEBUG_NEW - #undef THIS_FILE - static char THIS_FILE[] = __FILE__; -#endif - -CShapefile::CShapefile() -{ - CSingleLock sfLock(&ShapefileLock, TRUE); - - _pUnkMarshaler = nullptr; - - _sortingChanged = true; - _sortAscending = VARIANT_FALSE; - _sortField = SysAllocString(L""); - - _appendStartShapeCount = -1; - _appendMode = VARIANT_FALSE; - _snappable = VARIANT_TRUE; - _interactiveEditing = VARIANT_FALSE; - _hotTracking = VARIANT_TRUE; - _selectable = VARIANT_FALSE; - _geosGeometriesRead = false; - _stopExecution = nullptr; - - _selectionTransparency = 180; - _selectionAppearance = saSelectionColor; - _selectionColor = RGB(255, 255, 0); - _collisionMode = tkCollisionMode::LocalList; - - _geometryEngine = m_globalSettings.geometryEngine; - - _sourceType = sstUninitialized; - - _writing = false; - _reading = false; - - _isEditingShapes = FALSE; - _fastMode = m_globalSettings.shapefileFastMode ? TRUE : FALSE; - _minDrawingSize = 1; - _volatile = false; - - _useSpatialIndex = TRUE; - _hasSpatialIndex = FALSE; - _spatialIndexLoaded = FALSE; - _spatialIndexMaxAreaPercent = 0.5; - _spatialIndexNodeCapacity = 100; - - //Neio 20090721 - _useQTree = FALSE; - _cacheExtents = FALSE; - _qtree = nullptr; - _tempTree = nullptr; - - _shpfile = nullptr; - _shxfile = nullptr; - - _shpfiletype = SHP_NULLSHAPE; - _nextShapeHandle = 0; - - _minX = 0.0; - _minY = 0.0; - _minZ = 0.0; - _maxX = 0.0; - _maxY = 0.0; - _maxZ = 0.0; - _minM = 0.0; - _maxM = 0.0; - - _key = SysAllocString(L""); - _expression = SysAllocString(L""); - _globalCallback = nullptr; - _lastErrorCode = tkNO_ERROR; - _table = nullptr; - - // creation of children classes - _selectDrawOpt = nullptr; - _defaultDrawOpt = nullptr; - _labels = nullptr; - _categories = nullptr; - _charts = nullptr; - _geoProjection = nullptr; - - ComHelper::CreateInstance(idShapeValidationInfo, (IDispatch**)&_inputValidation); - ComHelper::CreateInstance(idShapeValidationInfo, (IDispatch**)&_outputValidation); - - CoCreateInstance(CLSID_ShapeDrawingOptions, nullptr, CLSCTX_INPROC_SERVER, IID_IShapeDrawingOptions, - (void**)&_selectDrawOpt); - CoCreateInstance(CLSID_ShapeDrawingOptions, nullptr, CLSCTX_INPROC_SERVER, IID_IShapeDrawingOptions, - (void**)&_defaultDrawOpt); - CoCreateInstance(CLSID_ShapefileCategories, nullptr, CLSCTX_INPROC_SERVER, IID_IShapefileCategories, - (void**)&_categories); - CoCreateInstance(CLSID_Labels, nullptr, CLSCTX_INPROC_SERVER, IID_ILabels, (void**)&_labels); - CoCreateInstance(CLSID_Charts, nullptr, CLSCTX_INPROC_SERVER, IID_ICharts, (void**)&_charts); - CoCreateInstance(CLSID_GeoProjection, nullptr, CLSCTX_INPROC_SERVER, IID_IGeoProjection, (void**)&_geoProjection); - - this->put_ReferenceToLabels(); - this->put_ReferenceToCategories(); - this->put_ReferenceToCharts(); - - ComHelper::CreateInstance(idUndoList, (IDispatch**)&_undoList); - - gReferenceCounter.AddRef(tkInterface::idShapefile); -} - -CShapefile::~CShapefile() -{ - CSingleLock sfLock(&ShapefileLock, TRUE); - - VARIANT_BOOL vbretval; - this->CShapefile::Close(&vbretval); - - SysFreeString(_key); - SysFreeString(_expression); - SysFreeString(_sortField); - - if (_selectDrawOpt != nullptr) - _selectDrawOpt->Release(); - - if (_defaultDrawOpt != nullptr) - _defaultDrawOpt->Release(); - - if (_labels != nullptr) - { - put_ReferenceToLabels(true); // labels class maybe referenced by client and won't be deleted as a result - _labels->Release(); // therefore we must clear the reference to the parent as it will be invalid - } - - if (_categories != nullptr) - { - put_ReferenceToCategories(true); - _categories->Release(); - } - - if (_charts != nullptr) - { - put_ReferenceToCharts(true); - _charts->Release(); - } - - if (_stopExecution) - _stopExecution->Release(); - - if (_geoProjection) - _geoProjection->Release(); - - if (_undoList) - { - _undoList->Release(); - } - gReferenceCounter.Release(tkInterface::idShapefile); -} - -std::vector* CShapefile::get_ShapeVector() -{ - CSingleLock sfLock(&ShapefileLock, TRUE); - return &_shapeData; -} - -IShapeWrapper* CShapefile::get_ShapeWrapper(int ShapeIndex) -{ - CSingleLock sfLock(&ShapefileLock, TRUE); - return ((CShape*)_shapeData[ShapeIndex]->shape)->get_ShapeWrapper(); -} - -IShapeData* CShapefile::get_ShapeRenderingData(int ShapeIndex) -{ - CSingleLock sfLock(&ShapefileLock, TRUE); - return _shapeData[ShapeIndex]->get_RenderingData(); -} - -void CShapefile::put_ShapeRenderingData(int ShapeIndex, CShapeData* data) -{ - CSingleLock sfLock(&ShapefileLock, TRUE); - return _shapeData[ShapeIndex]->put_RenderingData(data); -} - -void CShapefile::SetValidationInfo(IShapeValidationInfo* info, tkShapeValidationType validationType) -{ - CSingleLock sfLock(&ShapefileLock, TRUE); - ComHelper::SetRef(info, - (IDispatch**)&(validationType == svtInput ? _inputValidation : _outputValidation), true); -} - -#pragma region Properties - -// ************************************************************ -// get_EditingShapes() -// ************************************************************ -STDMETHODIMP CShapefile::get_EditingShapes(VARIANT_BOOL* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _isEditingShapes ? VARIANT_TRUE : VARIANT_FALSE; - return S_OK; -} - -// ************************************************************ -// get_LastErrorCode() -// ************************************************************ -STDMETHODIMP CShapefile::get_LastErrorCode(long* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _lastErrorCode; - _lastErrorCode = tkNO_ERROR; - return S_OK; -} - -// ************************************************************ -// get_CdlgFilter() -// ************************************************************ -STDMETHODIMP CShapefile::get_CdlgFilter(BSTR* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - *pVal = A2BSTR("ESRI Shapefiles (*.shp)|*.shp"); - return S_OK; -} - -// ************************************************************ -// LastInputValidation -// ************************************************************ -STDMETHODIMP CShapefile::get_LastInputValidation(IShapeValidationInfo** retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (_inputValidation) - _inputValidation->AddRef(); - *retVal = _inputValidation; - return S_OK; -} - -// ************************************************************ -// LastOutputValidation -// ************************************************************ -STDMETHODIMP CShapefile::get_LastOutputValidation(IShapeValidationInfo** retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (_outputValidation) - _outputValidation->AddRef(); - *retVal = _outputValidation; - return S_OK; -} - -// ************************************************************ -// get/put_GlobalCallback() -// ************************************************************ -STDMETHODIMP CShapefile::get_GlobalCallback(ICallback** pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - *pVal = _globalCallback; - if (_globalCallback != nullptr) - _globalCallback->AddRef(); - return S_OK; -} - -STDMETHODIMP CShapefile::put_GlobalCallback(ICallback* newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - ComHelper::SetRef(newVal, (IDispatch**)&_globalCallback); - if (_table != nullptr) - _table->put_GlobalCallback(newVal); - - return S_OK; -} - -// ************************************************************ -// StopExecution -// ************************************************************ -STDMETHODIMP CShapefile::put_StopExecution(IStopExecution* stopper) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - ComHelper::SetRef((IDispatch*)stopper, (IDispatch**)&_stopExecution, true); - return S_OK; -} - -// ************************************************************ -// get/put_Key() -// ************************************************************ -STDMETHODIMP CShapefile::get_Key(BSTR* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - *pVal = OLE2BSTR(_key); - return S_OK; -} - -STDMETHODIMP CShapefile::put_Key(BSTR newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - SysFreeString(_key); - _key = OLE2BSTR(newVal); - return S_OK; -} - -// ************************************************************ -// get/put_VisibilityExpression -// ************************************************************ -STDMETHODIMP CShapefile::get_VisibilityExpression(BSTR* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - *pVal = OLE2BSTR(_expression); - return S_OK; -} - -STDMETHODIMP CShapefile::put_VisibilityExpression(BSTR newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - SysFreeString(_expression); - _expression = OLE2BSTR(newVal); - return S_OK; -} - -// ************************************************************ -// get/put_Volatile -// ************************************************************ -STDMETHODIMP CShapefile::get_Volatile(VARIANT_BOOL* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (_interactiveEditing) - { - *pVal = VARIANT_TRUE; - } - else - { - *pVal = _volatile ? VARIANT_TRUE : VARIANT_FALSE; - } - return S_OK; -} - -STDMETHODIMP CShapefile::put_Volatile(VARIANT_BOOL newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - _volatile = newVal == VARIANT_TRUE; - return S_OK; -} - -// ***************************************************************** -// get_NumShapes() -// ***************************************************************** -STDMETHODIMP CShapefile::get_NumShapes(long* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _shapeData.size(); //_numShapes; - return S_OK; -} - -// ************************************************************** -// get_NumFields() -// ************************************************************** -STDMETHODIMP CShapefile::get_NumFields(long* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (_table != nullptr) - _table->get_NumFields(pVal); - else - { - ErrorMessage(tkFILE_NOT_OPEN); - *pVal = 0; - } - return S_OK; -} - -// ************************************************************ -// get_ShapefileType() -// ************************************************************ -STDMETHODIMP CShapefile::get_ShapefileType(ShpfileType* pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _shpfiletype; - return S_OK; -} - -// ***************************************************************** -// get_ErrorMsg() -// ***************************************************************** -STDMETHODIMP CShapefile::get_ErrorMsg(long ErrorCode, BSTR* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - *pVal = A2BSTR(ErrorMsg(ErrorCode)); - return S_OK; -} - -// ***************************************************************** -// get_FileHandle() -// ***************************************************************** -STDMETHODIMP CShapefile::get_FileHandle(long* pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (_shpfile != nullptr) - { - const int handle = _fileno(_shpfile); - *pVal = _dup(handle); - } - else - *pVal = -1; - - return S_OK; -} - -// ************************************************************** -// get_Filename() -// ************************************************************** -STDMETHODIMP CShapefile::get_Filename(BSTR* pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - *pVal = W2BSTR(_shpfileName); - - return S_OK; -} - -// ************************************************************** -// ErrorMessage() -// ************************************************************** -void CShapefile::ErrorMessage(long ErrorCode) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - _lastErrorCode = ErrorCode; - CallbackHelper::ErrorMsg("Shapefile", _globalCallback, _key, ErrorMsg(_lastErrorCode)); -} - -void CShapefile::ErrorMessage(long ErrorCode, ICallback* cBack) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - _lastErrorCode = ErrorCode; - CallbackHelper::ErrorMsg("Shapefile", _globalCallback, _key, ErrorMsg(_lastErrorCode)); - if (cBack != _globalCallback) - CallbackHelper::ErrorMsg("Shapefile", cBack, _key, ErrorMsg(_lastErrorCode)); -} - -// ************************************************************ -// get_MinDrawingSize() -// ************************************************************ -STDMETHODIMP CShapefile::get_MinDrawingSize(LONG* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _minDrawingSize; - return S_OK; -} - -STDMETHODIMP CShapefile::put_MinDrawingSize(LONG newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - _minDrawingSize = newVal; - return S_OK; -} - -// ************************************************************ -// get_SourceType() -// ************************************************************ -STDMETHODIMP CShapefile::get_SourceType(tkShapefileSourceType* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _sourceType; - return S_OK; -} - -#pragma endregion - -#pragma region CreateAndOpen - - -// ************************************************************ -// LoadDataFrom() -// ************************************************************ -// Loads shape and DBF data from disk file into in-memory mode -STDMETHODIMP CShapefile::LoadDataFrom(BSTR ShapefileName, ICallback* cBack, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - USES_CONVERSION; - *retval = VARIANT_FALSE; - if (_sourceType != sstInMemory) - { - ErrorMessage(tkINMEMORY_SHAPEFILE_EXPECTED); - return S_OK; - } - - if (OpenCore(OLE2CA(ShapefileName), cBack)) - { - // loading data in-memory - VARIANT_BOOL vb; - _isEditingShapes = false; - StartEditingShapes(VARIANT_TRUE, cBack, &vb); - - // this will trigger loading of all DBF values into the memory - long numFields; - this->get_NumFields(&numFields); - if (numFields > 0) - { - CComVariant var; - for (size_t i = 0; i < _shapeData.size(); i++) - { - _table->get_CellValue(0, i, &var); - } - } - - // closing disk file despite the result success or failure - _shpfileName = ""; - _shxfileName = ""; - _dbffileName = ""; - - if (_shpfile != nullptr) - fclose(_shpfile); - _shpfile = nullptr; - - if (_shxfile != nullptr) - fclose(_shxfile); - _shxfile = nullptr; - - if (_table != nullptr) - ((CTableClass*)_table)->CloseUnderlyingFile(); - - *retval = vb; - } - return S_OK; -} - -// ************************************************************ -// OpenCore() -// ************************************************************ -bool CShapefile::OpenCore(CStringW tmpShpfileName, ICallback* cBack) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - VARIANT_BOOL vbretval; - - // saving the provided names; - // from now on we must clean the class variables in case the operation won't succeed - _shpfileName = tmpShpfileName; - _shxfileName = tmpShpfileName.Left(tmpShpfileName.GetLength() - 3) + L"shx"; - _dbffileName = tmpShpfileName.Left(tmpShpfileName.GetLength() - 3) + L"dbf"; - _prjfileName = tmpShpfileName.Left(tmpShpfileName.GetLength() - 3) + L"prj"; - - // read mode - _shpfile = _wfopen(_shpfileName, L"rb"); - _shxfile = _wfopen(_shxfileName, L"rb"); - - // opening DBF - if (!_table) - { - CoCreateInstance(CLSID_Table, nullptr, CLSCTX_INPROC_SERVER, IID_ITable, (void**)&_table); - } - else - { - VARIANT_BOOL vb; - _table->Close(&vb); - } - - _table->put_GlobalCallback(_globalCallback); - ((CTableClass*)_table)->InjectShapefile(this); - - const CComBSTR bstrDbf(_dbffileName); - _table->Open(bstrDbf, cBack, &vbretval); - - if (_shpfile == nullptr) - { - ErrorMessage(tkCANT_OPEN_SHP); - this->Close(&vbretval); - } - else if (_shxfile == nullptr) - { - ErrorMessage(tkCANT_OPEN_SHX); - this->Close(&vbretval); - } - else if (vbretval == VARIANT_FALSE) - { - _table->get_LastErrorCode(&_lastErrorCode); - ErrorMessage(_lastErrorCode); - this->Close(&vbretval); - } - else - { - if (!ReadShx()) // shapefile header is read here as well - { - ErrorMessage(tkINVALID_SHX_FILE); - this->Close(&vbretval); - } - else - { - //Check for supported types - if (_shpfiletype != SHP_NULLSHAPE && - _shpfiletype != SHP_POINT && - _shpfiletype != SHP_POLYLINE && - _shpfiletype != SHP_POLYGON && - _shpfiletype != SHP_POINTZ && - _shpfiletype != SHP_POLYLINEZ && - _shpfiletype != SHP_POLYGONZ && - _shpfiletype != SHP_MULTIPOINT && - _shpfiletype != SHP_MULTIPOINTZ && - _shpfiletype != SHP_POLYLINEM && - _shpfiletype != SHP_POLYGONM && - _shpfiletype != SHP_POINTM && - _shpfiletype != SHP_MULTIPOINTM) - { - ErrorMessage(tkUNSUPPORTED_SHAPEFILE_TYPE); - this->Close(&vbretval); - } - else - { - _shapeData.reserve(_shpOffsets.size()); - for (size_t i = 0; i < _shpOffsets.size(); i++) - { - _shapeData.push_back(new ShapeRecord()); - } - return true; - } - } - } - return false; -} - -// ************************************************************ -// Open() -// ************************************************************ -STDMETHODIMP CShapefile::Open(BSTR ShapefileName, ICallback* cBack, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - VARIANT_BOOL vbretval; - - if (_globalCallback == nullptr && cBack != nullptr) - { - _globalCallback = cBack; - _globalCallback->AddRef(); - } - - USES_CONVERSION; - CStringW tmp_shpfileName = OLE2CW(ShapefileName); - - if (tmp_shpfileName.GetLength() == 0) - { - // better to use CreateNew directly, but this call will be preserved for backward compatibility - this->CreateNew(m_globalSettings.emptyBstr, _shpfiletype, &vbretval); - } - else if (tmp_shpfileName.GetLength() <= 3) - { - ErrorMessage(tkINVALID_FILENAME); - } - else - { - // close the opened shapefile - this->Close(&vbretval); - - if (vbretval == VARIANT_FALSE) - { - // error code in the function - return S_OK; - } - - if (OpenCore(tmp_shpfileName, cBack)) - { - _sourceType = sstDiskBased; - - // reading projection - const CComBSTR bstrPrj(_prjfileName); - _geoProjection->ReadFromFileEx(bstrPrj, VARIANT_TRUE, &vbretval); - - ShapeStyleHelper::ApplyRandomDrawingOptions(this); - LabelsHelper::UpdateLabelsPositioning(this); - *retval = VARIANT_TRUE; - } - } - return S_OK; -} - -// ********************************************************* -// CreateNew() -// ********************************************************* -STDMETHODIMP CShapefile::CreateNew(BSTR ShapefileName, ShpfileType ShapefileType, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - return this->CreateNewCore(ShapefileName, ShapefileType, true, retval); -} - -// ********************************************************* -// CreateNewCore() -// ********************************************************* -HRESULT CShapefile::CreateNewCore(BSTR ShapefileName, ShpfileType ShapefileType, bool applyRandomOptions, - VARIANT_BOOL* retval) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - VARIANT_BOOL vb; - - // check for supported types - if (ShapefileType != SHP_NULLSHAPE && - ShapefileType != SHP_POINT && - ShapefileType != SHP_POLYLINE && - ShapefileType != SHP_POLYGON && - ShapefileType != SHP_POINTZ && - ShapefileType != SHP_POLYLINEZ && - ShapefileType != SHP_POLYGONZ && - ShapefileType != SHP_MULTIPOINT && - ShapefileType != SHP_MULTIPOINTZ && - ShapefileType != SHP_POINTM && // MWGIS-69 - ShapefileType != SHP_POLYLINEM && - ShapefileType != SHP_POLYGONM && - ShapefileType != SHP_MULTIPOINTM) - { - ErrorMessage(tkUNSUPPORTED_SHAPEFILE_TYPE); - return S_OK; - } - - USES_CONVERSION; - CString tmp_shpfileName = OLE2CA(ShapefileName); - - // ---------------------------------------------- - // in memory shapefile (without name) - // ---------------------------------------------- - if (tmp_shpfileName.GetLength() == 0) - { - // closing the old shapefile (error code inside the function) - Close(&vb); - - if (vb == VARIANT_TRUE) - { - CoCreateInstance(CLSID_Table, nullptr, CLSCTX_INPROC_SERVER, IID_ITable, (void**)&_table); - - _table->CreateNew(m_globalSettings.emptyBstr, &vb); - - if (!vb) - { - long error; - _table->get_LastErrorCode(&error); - ErrorMessage(error); - _table->Release(); - _table = nullptr; - } - else - { - _shpfiletype = ShapefileType; - _isEditingShapes = true; - _sourceType = sstInMemory; - - if (applyRandomOptions) - { - ShapeStyleHelper::ApplyRandomDrawingOptions(this); - } - - *retval = VARIANT_TRUE; - } - } - - return S_OK; - } - - if (tmp_shpfileName.GetLength() <= 3) - { - ErrorMessage(tkINVALID_FILENAME); - return S_OK; - } - - const CString& shpName = tmp_shpfileName; - const CString shxName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "shx"; - const CString dbfName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "dbf"; - const CString prjName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "prj"; - - // new file is created, so there must not be any files with this names - if (Utility::FileExists(shpName) != FALSE) - { - ErrorMessage(tkSHP_FILE_EXISTS); - return S_OK; - } - if (Utility::FileExists(shxName) != FALSE) - { - ErrorMessage(tkSHX_FILE_EXISTS); - return S_OK; - } - if (Utility::FileExists(dbfName) != FALSE) - { - ErrorMessage(tkDBF_FILE_EXISTS); - return S_OK; - } - if (Utility::FileExists(prjName) != FALSE) - { - ErrorMessage(tkPRJ_FILE_EXISTS); - return S_OK; - } - - // closing the old shapefile (error code inside the function) - this->Close(&vb); - - if (vb == VARIANT_TRUE) - { - CoCreateInstance(CLSID_Table, nullptr, CLSCTX_INPROC_SERVER, IID_ITable, (void**)&_table); - - _table->put_GlobalCallback(_globalCallback); - - const CString newDbfName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "dbf"; - const CComBSTR bstrName(newDbfName); - _table->CreateNew(bstrName, &vb); - - if (!vb) - { - _table->get_LastErrorCode(&_lastErrorCode); - ErrorMessage(_lastErrorCode); - _table->Release(); - _table = nullptr; - } - else - { - _shpfileName = tmp_shpfileName; - _shxfileName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "shx"; - _dbffileName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "dbf"; - _prjfileName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "prj"; - - _shpfiletype = ShapefileType; - _isEditingShapes = true; - _sourceType = sstInMemory; - - if (applyRandomOptions) - { - ShapeStyleHelper::ApplyRandomDrawingOptions(this); - } - - *retval = VARIANT_TRUE; - } - } - - LabelsHelper::UpdateLabelsPositioning(this); - - return S_OK; -} - -// ********************************************************* -// CreateNewWithShapeID() -// ********************************************************* -STDMETHODIMP CShapefile::CreateNewWithShapeID(BSTR ShapefileName, ShpfileType ShapefileType, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - USES_CONVERSION; - CSingleLock sfLock(&ShapefileLock, TRUE); - - CreateNew(ShapefileName, ShapefileType, retval); - - if (*retval) - ShapefileHelper::InsertMwShapeIdField(this); - - return S_OK; -} - -#pragma endregion - -#pragma region SaveAndClose -// ***************************************************************** -// Close() -// ***************************************************************** -STDMETHODIMP CShapefile::Close(VARIANT_BOOL* retval) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - - if (_appendMode) - { - StopAppendMode(); - } - - ClearCachedGeometries(); - - if (_isEditingShapes) - { - // just stop editing shapes, if the shape is in open status - this->StopEditingShapes(VARIANT_FALSE, VARIANT_TRUE, nullptr, retval); - } - - // stop editing table in case only it have been edited - VARIANT_BOOL isEditingTable = VARIANT_FALSE; - if (_table) - { - _table->get_EditingTable(&isEditingTable); - if (isEditingTable) - { - this->StopEditingTable(VARIANT_FALSE, _globalCallback, retval); - _table->get_EditingTable(&isEditingTable); - } - } - - // removing shape data - this->ReleaseMemoryShapes(); - for (auto& i : _shapeData) - { - delete i; - } - _shapeData.clear(); - - if (_spatialIndexLoaded) - IndexSearching::unloadSpatialIndex(_spatialIndexID); - - _sourceType = sstUninitialized; - _shpfiletype = SHP_NULLSHAPE; - LabelsHelper::UpdateLabelsPositioning(this); - - _shpfileName = ""; - _shxfileName = ""; - _dbffileName = ""; - - _minX = 0.0; - _minY = 0.0; - _minZ = 0.0; - _maxX = 0.0; - _maxY = 0.0; - _maxZ = 0.0; - _minM = 0.0; - _maxM = 0.0; - - if (_inputValidation != nullptr) - { - _inputValidation->Release(); - _inputValidation = nullptr; - } - - if (_outputValidation != nullptr) - { - _outputValidation->Release(); - _outputValidation = nullptr; - } - - if (_shpfile != nullptr) fclose(_shpfile); - _shpfile = nullptr; - - if (_shxfile != nullptr) fclose(_shxfile); - _shxfile = nullptr; - - if (_table != nullptr) - { - VARIANT_BOOL vbretval; - _table->Close(&vbretval); - _table->Release(); - _table = nullptr; - } - if (_labels) - { - _labels->Clear(); - _labels->ClearCategories(); - } - if (_charts) - { - _charts->Clear(); - } - if (_categories) - { - _categories->Clear(); - } - *retval = VARIANT_TRUE; - - return S_OK; -} - -// ********************************************************** -// Dump() -// ********************************************************** -//Saves shapefile without reopening it in a new location -STDMETHODIMP CShapefile::Dump(BSTR ShapefileName, ICallback* cBack, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - - const bool callbackIsNull = _globalCallback == nullptr; - if (_globalCallback == nullptr && cBack != nullptr) - { - _globalCallback = cBack; - _globalCallback->AddRef(); - } - - if (_table == nullptr || _sourceType == sstUninitialized) - { - ErrorMessage(tkSHAPEFILE_UNINITIALIZED); - return S_OK; - } - - // in case someone else is writing, we leave - if (_writing) - { - ErrorMessage(tkSHP_WRITE_VIOLATION); - return S_OK; - } - - if (!this->ValidateOutput(this, "Dump", "Shapefile", false)) - return S_OK; - - USES_CONVERSION; - CString sa_shpfileName = OLE2CA(ShapefileName); - - if (sa_shpfileName.GetLength() <= 3) - { - ErrorMessage(tkINVALID_FILENAME); - } - else - { - const CString sa_shxfileName = sa_shpfileName.Left(sa_shpfileName.GetLength() - 3) + "shx"; - CString sa_dbffileName = sa_shpfileName.Left(sa_shpfileName.GetLength() - 3) + "dbf"; - - // ----------------------------------------------- - // it's not allowed to rewrite the existing files - // ----------------------------------------------- - if (Utility::FileExists(sa_shpfileName)) - { - ErrorMessage(tkSHP_FILE_EXISTS); - return S_OK; - } - if (Utility::FileExists(sa_shxfileName)) - { - ErrorMessage(tkSHX_FILE_EXISTS); - return S_OK; - } - if (Utility::FileExists(sa_dbffileName)) - { - ErrorMessage(tkDBF_FILE_EXISTS); - return S_OK; - } - - // ----------------------------------------------- - // checking in-memory shapes - // ----------------------------------------------- - if (_isEditingShapes) - { - if (VerifyMemShapes(cBack) == FALSE) - { - // error Code is set in function - return S_OK; - } - - // refresh extents - VARIANT_BOOL retVal; - this->RefreshExtents(&retVal); - } - - // ----------------------------------------------- - // opening files - // ----------------------------------------------- - FILE* shpfile = fopen(sa_shpfileName, "wb+"); - if (shpfile == nullptr) - { - ErrorMessage(tkCANT_CREATE_SHP); - return S_OK; - } - - //shx - FILE* shxfile = fopen(sa_shxfileName, "wb+"); - if (shxfile == nullptr) - { - fclose(shpfile); - ErrorMessage(tkCANT_CREATE_SHX); - return S_OK; - } - - // ------------------------------------------------ - // writing the files - // ------------------------------------------------ - this->WriteShp(shpfile, cBack); - this->WriteShx(shxfile, cBack); - - fclose(shpfile); - fclose(shxfile); - - // ------------------------------------------------ - // saving dbf table - // ------------------------------------------------ - _table->Dump(sa_dbffileName.AllocSysString(), cBack, retval); - if (*retval == FALSE) - { - _table->get_LastErrorCode(&_lastErrorCode); - return S_OK; - } - - // saving projection in new format - VARIANT_BOOL vbretval; - const CStringW prjfileName = sa_shpfileName.Left(sa_shpfileName.GetLength() - 3) + L"prj"; - const CComBSTR bstr(prjfileName); - _geoProjection->WriteToFileEx(bstr, VARIANT_TRUE, &vbretval); - - *retval = VARIANT_TRUE; - } - - // restoring callback - if (callbackIsNull) - { - _globalCallback = nullptr; - } - - return S_OK; -} - -// ********************************************************** -// SaveAs() -// ********************************************************** -// Saves shapefile to the new or the same location. Doesn't stop editing mode. -STDMETHODIMP CShapefile::SaveAs(BSTR ShapefileName, ICallback* cBack, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - - const bool callbackIsNull = _globalCallback == nullptr; - if (_globalCallback == nullptr && cBack != nullptr) - { - _globalCallback = cBack; - _globalCallback->AddRef(); - } - - if (_table == nullptr || _sourceType == sstUninitialized) - { - ErrorMessage(tkSHAPEFILE_UNINITIALIZED); - return S_OK; - } - - // in case someone else is writing, we leave - if (_writing) - { - ErrorMessage(tkSHP_WRITE_VIOLATION); - return S_OK; - } - - if (!this->ValidateOutput(this, "SaveAs", "Shapefile", false)) - return S_OK; - - USES_CONVERSION; - CStringW newShpName = OLE2W(ShapefileName); - - if (newShpName.GetLength() <= 3) - { - ErrorMessage(tkINVALID_FILENAME); - } - else if (!Utility::EndsWith(newShpName, L".shp")) - { - ErrorMessage(tkINVALID_FILE_EXTENSION); - } - else - { - const CStringW newShxName = newShpName.Left(newShpName.GetLength() - 3) + L"shx"; - const CStringW newDbfName = newShpName.Left(newShpName.GetLength() - 3) + L"dbf"; - - // ----------------------------------------------- - // it's not allowed to rewrite the existing files - // ----------------------------------------------- - if (Utility::FileExistsW(newShpName)) - { - ErrorMessage(tkSHP_FILE_EXISTS); - return S_OK; - } - if (Utility::FileExistsW(newShxName)) - { - ErrorMessage(tkSHX_FILE_EXISTS); - return S_OK; - } - if (Utility::FileExistsW(newDbfName)) - { - ErrorMessage(tkDBF_FILE_EXISTS); - return S_OK; - } - - // ----------------------------------------------- - // checking in-memory shapes - // ----------------------------------------------- - if (_isEditingShapes) - { - if (VerifyMemShapes(cBack) == FALSE) - { - // error Code is set in function - return S_OK; - } - - // refresh extents - VARIANT_BOOL retVal; - RefreshExtents(&retVal); - } - - // ----------------------------------------------- - // opening files - // ----------------------------------------------- - FILE* shpfile = _wfopen(newShpName, L"wb+"); - if (shpfile == nullptr) - { - ErrorMessage(tkCANT_CREATE_SHP); - return S_OK; - } - - //shx - FILE* shxfile = _wfopen(newShxName, L"wb+"); - if (shxfile == nullptr) - { - fclose(shpfile); - ErrorMessage(tkCANT_CREATE_SHX); - return S_OK; - } - - // ------------------------------------------------ - // writing the files - // ------------------------------------------------ - WriteShp(shpfile, cBack); - WriteShx(shxfile, cBack); - - fclose(shpfile); - fclose(shxfile); - - // ------------------------------------------------ - // saving dbf table - // ------------------------------------------------ - const CComBSTR bstrDbf(newDbfName); - _table->SaveAs(bstrDbf, cBack, retval); - - if (*retval != VARIANT_TRUE) - { - _table->get_LastErrorCode(&_lastErrorCode); - _wunlink(newShpName); - _wunlink(newShxName); - return S_OK; - } - - // ------------------------------------------------- - // switching to the new files - // ------------------------------------------------- - shpfile = _wfopen(newShpName, L"rb"); - shxfile = _wfopen(newShxName, L"rb"); - - if (_shpfile != nullptr) fclose(_shpfile); - _shpfile = shpfile; - - if (_shxfile != nullptr) fclose(_shxfile); - _shxfile = shxfile; - - // update all filenames: - _shpfileName = newShpName; // saving of shp filename should be done before writing the projection; - _shxfileName = newShxName; // otherwise projection string will be written to the memory - _dbffileName = newDbfName; - _prjfileName = newShpName.Left(newShpName.GetLength() - 3) + L"prj"; - - _sourceType = sstDiskBased; - - // saving projection in new format - VARIANT_BOOL vbretval, isEmpty; - _geoProjection->get_IsEmpty(&isEmpty); - if (!isEmpty) - { - const CComBSTR bstr(_prjfileName); - _geoProjection->WriteToFileEx(bstr, VARIANT_TRUE, &vbretval); - } - - if (_useQTree) - GenerateQTree(); - - *retval = VARIANT_TRUE; - } - - // restoring callback - if (callbackIsNull) - { - _globalCallback = nullptr; - } - - return S_OK; -} - -// ************************************************************** -// Save() -// ************************************************************** -// saving without exiting edit mode -STDMETHODIMP CShapefile::Save(ICallback* cBack, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - - if (_globalCallback == nullptr && cBack != nullptr) - { - _globalCallback = cBack; - _globalCallback->AddRef(); - } - - // no edits were made; it doesn't make sense to save it - if (_isEditingShapes == FALSE) - { - ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); - return S_OK; - } - - if (VerifyMemShapes(_globalCallback) == FALSE) - { - // error Code is set in function - return S_OK; - } - - if (!this->ValidateOutput(this, "Save", "Shapefile", false)) - return S_OK; - - // compute the extents - VARIANT_BOOL res; - RefreshExtents(&res); - - // ------------------------------------------------- - // Reopen the files in the write mode - // ------------------------------------------------- - if (_shpfile && _shxfile) - { - _shpfile = _wfreopen(_shpfileName, L"wb+", _shpfile); - _shxfile = _wfreopen(_shxfileName, L"wb+", _shxfile); - } - else - { - _shpfile = _wfopen(_shpfileName, L"wb+"); - _shxfile = _wfopen(_shxfileName, L"wb+"); - } - - if (_shpfile == nullptr || _shxfile == nullptr) - { - if (_shxfile != nullptr) - { - fclose(_shxfile); - _shxfile = nullptr; - _lastErrorCode = tkCANT_OPEN_SHX; - } - if (_shpfile != nullptr) - { - fclose(_shpfile); - _shpfile = nullptr; - _lastErrorCode = tkCANT_OPEN_SHP; - } - *retval = FALSE; - - ErrorMessage(_lastErrorCode); - } - else - { - _writing = true; - - // ------------------------------------------------- - // Writing the files - // ------------------------------------------------- - WriteShp(_shpfile, cBack); - WriteShx(_shxfile, cBack); - - if (_useQTree) - GenerateQTree(); - - // ------------------------------------------------- - // Reopen the updated files - // ------------------------------------------------- - _shpfile = _wfreopen(_shpfileName, L"rb+", _shpfile); - _shxfile = _wfreopen(_shxfileName, L"rb+", _shxfile); - - if (_shpfile == nullptr || _shxfile == nullptr) - { - if (_shxfile != nullptr) - { - fclose(_shxfile); - _shxfile = nullptr; - _lastErrorCode = tkCANT_OPEN_SHX; - } - if (_shpfile != nullptr) - { - fclose(_shpfile); - _shpfile = nullptr; - _lastErrorCode = tkCANT_OPEN_SHP; - } - *retval = FALSE; - - ErrorMessage(_lastErrorCode); - } - else - { - //Save the table file - _table->Save(cBack, retval); - - _sourceType = sstDiskBased; - - // saving projection in new format - VARIANT_BOOL vbretval, isEmpty; - _geoProjection->get_IsEmpty(&isEmpty); - if (!isEmpty) - { - const CComBSTR bstr(_prjfileName); - _geoProjection->WriteToFileEx(bstr, VARIANT_TRUE, &vbretval); - } - - *retval = VARIANT_TRUE; - } - } - - _writing = false; - return S_OK; -} - -// ************************************************************ -// Resource() -// ************************************************************ -STDMETHODIMP CShapefile::Resource(BSTR newShpPath, VARIANT_BOOL* retval) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - Close(retval); - Open(newShpPath, nullptr, retval); - return S_OK; -} -#pragma endregion - -// *********************************************************************** -// Clone() -// *********************************************************************** -// Creates new shapefile with the same type and fields as existing one -STDMETHODIMP CShapefile::Clone(IShapefile** retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - ShapefileHelper::CloneCore(this, retVal, _shpfiletype); - return S_OK; -} - -// ************************************************************ -// get_Extents() -// ************************************************************ -STDMETHODIMP CShapefile::get_Extents(IExtents** pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - IExtents* bBox = nullptr; - ComHelper::CreateExtents(&bBox); - - // Extents could change because of the moving of points of a single shape - // It's difficult to track such changes, so we still need to recalculate them - // here to enforce proper drawing; _fastMode mode - for those who want - // to call refresh extents theirselfs - if (!_fastMode) - { - VARIANT_BOOL vbretval; - this->RefreshExtents(&vbretval); - } - - bBox->SetBounds(_minX, _minY, _minZ, _maxX, _maxY, _maxZ); - bBox->SetMeasureBounds(_minM, _maxM); - *pVal = bBox; - - return S_OK; -} - -#pragma region AttributeTable -// **************************************************************** -// EditInsertField() -// **************************************************************** -STDMETHODIMP CShapefile::EditInsertField(IField* NewField, long* FieldIndex, ICallback* cBack, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - if (cBack == nullptr && _globalCallback != nullptr) - cBack = _globalCallback; - - if (_table != nullptr) - { - _table->EditInsertField(NewField, FieldIndex, cBack, retval); - } - else - { - *retval = VARIANT_FALSE; - _lastErrorCode = tkFILE_NOT_OPEN; - ErrorMessage(_lastErrorCode, cBack); - return S_OK; - } - - if (*retval == VARIANT_FALSE) - { - _table->get_LastErrorCode(&_lastErrorCode); - *retval = VARIANT_FALSE; - } - - return S_OK; -} - -// **************************************************************** -// EditDeleteField() -// **************************************************************** -STDMETHODIMP CShapefile::EditDeleteField(long FieldIndex, ICallback* cBack, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - if (_globalCallback == nullptr && cBack != nullptr) - { - _globalCallback = cBack; - _globalCallback->AddRef(); - } - - if (_table != nullptr) - { - _table->EditDeleteField(FieldIndex, cBack, retval); - } - else - { - *retval = VARIANT_FALSE; - ErrorMessage(tkFILE_NOT_OPEN); - return S_OK; - } - - if (*retval == VARIANT_FALSE) - { - _table->get_LastErrorCode(&_lastErrorCode); - *retval = VARIANT_FALSE; - } - - return S_OK; -} - -// **************************************************************** -// EditCellValue() -// **************************************************************** -STDMETHODIMP CShapefile::EditCellValue(long FieldIndex, long ShapeIndex, VARIANT NewVal, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - if (_table != nullptr) - { - _table->EditCellValue(FieldIndex, ShapeIndex, NewVal, retval); - } - else - { - *retval = VARIANT_FALSE; - ErrorMessage(tkFILE_NOT_OPEN); - return S_OK; - } - - if (*retval == VARIANT_FALSE) - { - _table->get_LastErrorCode(&_lastErrorCode); - } - - return S_OK; -} - -// **************************************************************** -// StartEditingTable() -// **************************************************************** -STDMETHODIMP CShapefile::StartEditingTable(ICallback* cBack, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - if (_appendMode) - { - ErrorMessage(tkDBF_NO_EDIT_MODE_WHEN_APPENDING); - *retval = VARIANT_FALSE; - return S_OK; - } - - if (_globalCallback == nullptr && cBack != nullptr) - { - _globalCallback = cBack; - _globalCallback->AddRef(); - } - - if (_table != nullptr) - { - _table->StartEditingTable(cBack, retval); - } - else - { - *retval = VARIANT_FALSE; - ErrorMessage(tkFILE_NOT_OPEN); - return S_OK; - } - - if (*retval == VARIANT_FALSE) - { - _table->get_LastErrorCode(&_lastErrorCode); - *retval = VARIANT_FALSE; - } - - return S_OK; -} - -// **************************************************************** -// StopEditingTable() -// **************************************************************** -STDMETHODIMP CShapefile::StopEditingTable(VARIANT_BOOL ApplyChanges, ICallback* cBack, VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - if (_globalCallback == nullptr && cBack != nullptr) - { - _globalCallback = cBack; - _globalCallback->AddRef(); - } - - if (_table != nullptr) - { - _table->StopEditingTable(ApplyChanges, cBack, retval); - } - else - { - *retval = VARIANT_FALSE; - ErrorMessage(tkFILE_NOT_OPEN); - return S_OK; - } - - if (*retval == FALSE) - { - _table->get_LastErrorCode(&_lastErrorCode); - *retval = VARIANT_FALSE; - } - - return S_OK; -} - -// ***************************************************************** -// get_Field() -// ***************************************************************** -STDMETHODIMP CShapefile::get_Field(long FieldIndex, IField** pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - if (_table != nullptr) - { - _table->get_Field(FieldIndex, pVal); - if (*pVal != nullptr) - { - // we need to report error from field class, and will use callback from this class for it - ICallback* cBack = nullptr; - if ((*pVal)->get_GlobalCallback(&cBack) == NULL && this->_globalCallback != nullptr) - (*pVal)->put_GlobalCallback(_globalCallback); - - if (cBack != nullptr) - cBack->Release(); // we put a reference in field class so must release it here - } - } - else - { - ErrorMessage(tkFILE_NOT_OPEN); - return S_OK; - } - - return S_OK; -} - -// ***************************************************************** -// get_FieldByName() -// ***************************************************************** -STDMETHODIMP CShapefile::get_FieldByName(BSTR Fieldname, IField** pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - - long max; - - CString strFieldname; - IField* testVal; - - _table->get_NumFields(&max); - if (_table != nullptr) - { - if (_tcslen(OLE2CA(Fieldname)) > 0) - { - strFieldname = OLE2A(Fieldname); - } - else - { - ErrorMessage(tkZERO_LENGTH_STRING); - } - - for (int fld = 0; fld < max; fld++) - { - _table->get_Field(fld, &testVal); - CComBSTR Testname; - testVal->get_Name(&Testname); - CString strTestname = OLE2A(Testname); - if (strTestname.CompareNoCase(strFieldname) == 0) - { - *pVal = testVal; - return S_OK; - } - testVal->Release(); - } - } - else - { - ErrorMessage(tkFILE_NOT_OPEN); - return S_OK; - } - - // we did not have a file error, but we also didn't match the name - pVal = nullptr; - return S_OK; -} - -// ***************************************************************** -// get_CellValue() -// ***************************************************************** -STDMETHODIMP CShapefile::get_CellValue(long FieldIndex, long ShapeIndex, VARIANT* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - if (_table != nullptr) - { - _table->get_CellValue(FieldIndex, ShapeIndex, pVal); - } - else - { - ErrorMessage(tkFILE_NOT_OPEN); - return S_OK; - } - - return S_OK; -} - -// ***************************************************************** -// get_EditingTable() -// ***************************************************************** -STDMETHODIMP CShapefile::get_EditingTable(VARIANT_BOOL* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (_table != nullptr) - { - _table->get_EditingTable(pVal); - } - else - { - *pVal = VARIANT_FALSE; - ErrorMessage(tkFILE_NOT_OPEN); - return S_OK; - } - - return S_OK; -} - -// ************************************************************* -// get_Table() -// ************************************************************* -STDMETHODIMP CShapefile::get_Table(ITable** retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retVal = _table; - if (_table) - { - _table->AddRef(); - } - return S_OK; -} -#pragma endregion - -#pragma region DrawingOptions - -// ************************************************************* -// get_ShapeRotation() -// ************************************************************* -STDMETHODIMP CShapefile::get_ShapeRotation(long ShapeIndex, double* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) - { - *pVal = -1; - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - *pVal = _shapeData[ShapeIndex]->rotation; - return S_OK; -} - -STDMETHODIMP CShapefile::put_ShapeRotation(long ShapeIndex, double newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - _shapeData[ShapeIndex]->rotation = static_cast(newVal); - - return S_OK; -} - -// ************************************************************* -// get_ShapeVisible() -// ************************************************************* -STDMETHODIMP CShapefile::get_ShapeVisible(long ShapeIndex, VARIANT_BOOL* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = VARIANT_FALSE; - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - // this particular shape was not hidden explicitly or via visibility expression - if (!_shapeData[ShapeIndex]->hidden() && _shapeData[ShapeIndex]->isVisible()) - { - long ctIndex = -1; - get_ShapeCategory(ShapeIndex, &ctIndex); - if (ctIndex == -1) - { - // no category, check default options - _defaultDrawOpt->get_Visible(pVal); - } - else - { - // there is category, check whether it is visible - CComPtr ct = nullptr; - get_ShapeCategory3(ShapeIndex, &ct); - if (ct) - { - CComPtr options = nullptr; - ct->get_DrawingOptions(&options); - if (options) - { - options->get_Visible(pVal); - } - } - } - } - } - return S_OK; -} - -// ************************************************************* -// ShapeIsHidden() -// ************************************************************* -STDMETHODIMP CShapefile::get_ShapeIsHidden(LONG shapeIndex, VARIANT_BOOL* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (shapeIndex < 0 || shapeIndex >= (long)_shapeData.size()) - { - *pVal = VARIANT_FALSE; - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - *pVal = _shapeData[shapeIndex]->hidden() ? VARIANT_TRUE : VARIANT_FALSE; - } - return S_OK; -} - -STDMETHODIMP CShapefile::put_ShapeIsHidden(LONG shapeIndex, VARIANT_BOOL newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (shapeIndex < 0 || shapeIndex >= (long)_shapeData.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - _shapeData[shapeIndex]->hidden(newVal != 0); - - return S_OK; -} - -// ************************************************************* -// get_ShapeModified() -// ************************************************************* -STDMETHODIMP CShapefile::get_ShapeModified(long ShapeIndex, VARIANT_BOOL* retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) - { - *retVal = -1; - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - *retVal = _shapeData[ShapeIndex]->modified() ? VARIANT_TRUE : VARIANT_FALSE; - } - - return S_OK; -} - -STDMETHODIMP CShapefile::put_ShapeModified(long ShapeIndex, VARIANT_BOOL newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - _shapeData[ShapeIndex]->modified(newVal != 0); - } - - return S_OK; -} - - -// ************************************************************* -// get_ShapeCategory() -// ************************************************************* -STDMETHODIMP CShapefile::get_ShapeCategory(long ShapeIndex, long* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) //_numShapes) - { - *pVal = -1; - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - *pVal = _shapeData[ShapeIndex]->category; - return S_OK; -} - -STDMETHODIMP CShapefile::put_ShapeCategory(long ShapeIndex, long newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) //_numShapes ) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - _shapeData[ShapeIndex]->category = (int)newVal; - - return S_OK; -} - -// ************************************************************* -// get_ShapeCategory2() -// ************************************************************* -STDMETHODIMP CShapefile::put_ShapeCategory2(long ShapeIndex, BSTR categoryName) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - int index; - _categories->get_CategoryIndexByName(categoryName, &index); - if (index == -1) - { - ErrorMessage(tkCATEGORY_WASNT_FOUND); - } - else - { - _shapeData[ShapeIndex]->category = (int)index; - } - } - return S_OK; -} - -STDMETHODIMP CShapefile::get_ShapeCategory2(long ShapeIndex, BSTR* categoryName) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - const int index = _shapeData[ShapeIndex]->category; - long count; - _categories->get_Count(&count); - if (index >= 0 && index < count) - { - IShapefileCategory* ct; - _categories->get_Item(index, &ct); - ct->get_Name(categoryName); - ct->Release(); - return S_OK; - } - ErrorMessage(tkCATEGORY_WASNT_FOUND); - } - *categoryName = SysAllocString(L""); - return S_OK; -} - -// ************************************************************* -// put_ShapeCategory3() -// ************************************************************* -STDMETHODIMP CShapefile::put_ShapeCategory3(long ShapeIndex, IShapefileCategory* category) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - int index; - _categories->get_CategoryIndex(category, &index); - if (index == -1) - { - ErrorMessage(tkCATEGORY_WASNT_FOUND); - } - else - { - _shapeData[ShapeIndex]->category = (int)index; - } - } - return S_OK; -} - -STDMETHODIMP CShapefile::get_ShapeCategory3(long ShapeIndex, IShapefileCategory** category) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *category = nullptr; - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - const int index = _shapeData[ShapeIndex]->category; - long count; - _categories->get_Count(&count); - if (index >= 0 && index < count) - { - IShapefileCategory* ct; - _categories->get_Item(index, &ct); - *category = ct; // ref was added in the get_Item - } - else - { - ErrorMessage(tkCATEGORY_WASNT_FOUND); - } - } - return S_OK; -} - -// ******************************************************************* -// SelectionDrawingOptions() -// ******************************************************************* -// Returns and sets parameters used to draw selection for the shapefile. -STDMETHODIMP CShapefile::get_SelectionDrawingOptions(IShapeDrawingOptions** pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _selectDrawOpt; - if (_selectDrawOpt) - _selectDrawOpt->AddRef(); - return S_OK; -} - -STDMETHODIMP CShapefile::put_SelectionDrawingOptions(IShapeDrawingOptions* newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (!newVal) - { - ErrorMessage(tkINVALID_PARAMETER_VALUE); - } - else - { - ComHelper::SetRef(newVal, (IDispatch**)&_selectDrawOpt, false); - } - return S_OK; -} - -// ******************************************************************* -// DeafultDrawingOptions() -// ******************************************************************* -// Returns and sets parameters used to draw shapefile by default. -STDMETHODIMP CShapefile::get_DefaultDrawingOptions(IShapeDrawingOptions** pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _defaultDrawOpt; - if (_defaultDrawOpt) - _defaultDrawOpt->AddRef(); - return S_OK; -} - -STDMETHODIMP CShapefile::put_DefaultDrawingOptions(IShapeDrawingOptions* newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - if (!newVal) - { - ErrorMessage(tkINVALID_PARAMETER_VALUE); - } - else - { - ComHelper::SetRef(newVal, (IDispatch**)&_defaultDrawOpt); - } - return S_OK; -} - -// *********************************************************************** -// put_ReferenceToCategories -// *********************************************************************** -void CShapefile::put_ReferenceToCategories(bool bNullReference) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (_categories == nullptr) return; - auto* coCategories = dynamic_cast(_categories); - if (!bNullReference) - coCategories->put_ParentShapefile(this); - else - coCategories->put_ParentShapefile(nullptr); -}; - -// *********************************************************************** -// get/put_Categories -// *********************************************************************** -STDMETHODIMP CShapefile::get_Categories(IShapefileCategories** pVal) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _categories; - if (_categories != nullptr) - _categories->AddRef(); - return S_OK; -} - -STDMETHODIMP CShapefile::put_Categories(IShapefileCategories* newVal) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (ComHelper::SetRef((IDispatch*)newVal, (IDispatch**)&_categories, false)) - { - ((CShapefileCategories*)_categories)->put_ParentShapefile(this); - } - return S_OK; -} -#pragma endregion - -// ******************************************************************** -// get_SelectionColor -// ******************************************************************** -STDMETHODIMP CShapefile::get_SelectionColor(OLE_COLOR* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = _selectionColor; - return S_OK; -} - -STDMETHODIMP CShapefile::put_SelectionColor(OLE_COLOR newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - _selectionColor = newVal; - return S_OK; -} - -// ******************************************************************** -// get_SelectionTransparency -// ******************************************************************** -STDMETHODIMP CShapefile::get_SelectionTransparency(BYTE* retval) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - *retval = _selectionTransparency; - return S_OK; -} - -STDMETHODIMP CShapefile::put_SelectionTransparency(BYTE newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (newVal > 255) newVal = 255; - _selectionTransparency = newVal; - return S_OK; -} - -// ******************************************************************** -// get_SelectionAppearance -// ******************************************************************** -STDMETHODIMP CShapefile::get_SelectionAppearance(tkSelectionAppearance* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = _selectionAppearance; - return S_OK; -} - -STDMETHODIMP CShapefile::put_SelectionAppearance(tkSelectionAppearance newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - _selectionAppearance = newVal; - return S_OK; -} - -// ******************************************************************** -// get_PointCollisionMode -// ******************************************************************** -STDMETHODIMP CShapefile::get_CollisionMode(tkCollisionMode* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = _collisionMode; - return S_OK; -} - -STDMETHODIMP CShapefile::put_CollisionMode(tkCollisionMode newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - _collisionMode = newVal; - return S_OK; -} - -#pragma region "Seialization" -// ******************************************************** -// Serialize() -// ******************************************************** -STDMETHODIMP CShapefile::Serialize(VARIANT_BOOL SaveSelection, BSTR* retVal) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - return Serialize2(SaveSelection, VARIANT_FALSE, retVal); -} - -STDMETHODIMP CShapefile::Serialize2(VARIANT_BOOL SaveSelection, VARIANT_BOOL SerializeCategories, BSTR* retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - CPLXMLNode* psTree = this->SerializeCore(VARIANT_TRUE, "ShapefileClass", SerializeCategories != 0); - Utility::SerializeAndDestroyXmlTree(psTree, retVal); - return S_OK; -} - -// ******************************************************** -// SerializeCore() -// ******************************************************** -CPLXMLNode* CShapefile::SerializeCore(VARIANT_BOOL SaveSelection, CString ElementName, bool serializeCategories) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - - CPLXMLNode* psTree = CPLCreateXMLNode(nullptr, CXT_Element, ElementName); - - if (psTree) - { - CString s = OLE2CA(_expression); - if (s != "") - Utility::CPLCreateXMLAttributeAndValue(psTree, "VisibilityExpression", s); - - - if (_useQTree != FALSE) - Utility::CPLCreateXMLAttributeAndValue(psTree, "UseQTree", CPLString().Printf("%d", (int)_useQTree)); - - if (_collisionMode != LocalList) - Utility::CPLCreateXMLAttributeAndValue(psTree, "CollisionMode", - CPLString().Printf("%d", (int)_collisionMode)); - - if (_selectionAppearance != saSelectionColor) - Utility::CPLCreateXMLAttributeAndValue(psTree, "SelectionAppearance", - CPLString().Printf("%d", (int)_selectionAppearance)); - - if (_selectionColor != RGB(255, 255, 0)) - Utility::CPLCreateXMLAttributeAndValue(psTree, "SelectionColor", - CPLString().Printf("%d", (int)_selectionColor)); - - if (_selectionTransparency != 180) - Utility::CPLCreateXMLAttributeAndValue(psTree, "SelectionTransparency", - CPLString().Printf("%d", (int)_selectionTransparency)); - - if (_minDrawingSize != 1) - Utility::CPLCreateXMLAttributeAndValue(psTree, "MinDrawingSize", CPLString().Printf("%d", _minDrawingSize)); - - // for in-memory shapefiles only - if (_sourceType == sstInMemory) - Utility::CPLCreateXMLAttributeAndValue(psTree, "ShpType", - CPLString().Printf("%d", (int)this->_shpfiletype)); - - s = OLE2CA(_sortField); - if (s != "") - Utility::CPLCreateXMLAttributeAndValue(psTree, "SortField", s); - - if (_sortAscending != VARIANT_FALSE) - Utility::CPLCreateXMLAttributeAndValue(psTree, "SortAscending", - CPLString().Printf("%d", (int)_sortAscending)); - - // drawing options - CPLXMLNode* node = ((CShapeDrawingOptions*)_defaultDrawOpt)->SerializeCore("DefaultDrawingOptions"); - if (node) - { - CPLAddXMLChild(psTree, node); - } - - if (_selectionAppearance == saDrawingOptions) - { - node = ((CShapeDrawingOptions*)_selectDrawOpt)->SerializeCore("SelectionDrawingOptions"); - if (node) - { - CPLAddXMLChild(psTree, node); - } - } - - // categories - node = ((CShapefileCategories*)_categories)->SerializeCore("ShapefileCategoriesClass"); - if (node) - { - CPLAddXMLChild(psTree, node); - } - - // labels - CPLXMLNode* psLabels = ((CLabels*)_labels)->SerializeCore("LabelsClass"); - if (psLabels) - { - CPLAddXMLChild(psTree, psLabels); - } - - // charts - CPLXMLNode* psCharts = ((CCharts*)_charts)->SerializeCore("ChartsClass"); - if (psCharts) - { - CPLAddXMLChild(psTree, psCharts); - } - - // ---------------------------------------------------- - // selection - // ---------------------------------------------------- - long numSelected; - this->get_NumSelected(&numSelected); - - if (numSelected > 0 && SaveSelection) - { - auto* selection = new char[_shapeData.size() + 1]; - selection[_shapeData.size()] = '\0'; - for (unsigned int i = 0; i < _shapeData.size(); i++) - { - selection[i] = _shapeData[i]->selected() ? '1' : '0'; - } - - CPLXMLNode* nodeSelection = CPLCreateXMLElementAndValue(psTree, "Selection", selection); - if (nodeSelection) - { - Utility::CPLCreateXMLAttributeAndValue(nodeSelection, "TotalCount", - CPLString().Printf("%d", _shapeData.size())); - Utility::CPLCreateXMLAttributeAndValue(nodeSelection, "SelectedCount", - CPLString().Printf("%d", numSelected)); - } - delete[] selection; - } - - // ---------------------------------------------------- - // serialization of category indices - // ---------------------------------------------------- - // Paul Meems TODO: This variable comes in as a parameter as well. - // Is this correct? - bool serializeCategories = false; - - for (auto& i : _shapeData) - { - if (i->category != -1) - { - serializeCategories = true; - } - } - - if (serializeCategories) - { - s = ""; - // doing it with CString is ugly of course, better to allocate a buffer - CString temp; - for (auto& i : _shapeData) - { - temp.Format("%d,", i->category); - s += temp; - } - - // when there are no indices assigned, write an empty node with Count = 0; - // to signal, that categories must not be applied automatically (behavior for older versions) - CPLXMLNode* nodeCats = CPLCreateXMLElementAndValue(psTree, "CategoryIndices", s.GetBuffer()); - if (nodeCats) - { - Utility::CPLCreateXMLAttributeAndValue(nodeCats, "Count", - CPLString().Printf( - "%d", serializeCategories ? _shapeData.size() : 0)); - } - } - - // ---------------------------------------------------- - // table - // ---------------------------------------------------- - if (_table) - { - CPLXMLNode* psTable = ((CTableClass*)_table)->SerializeCore("TableClass"); - if (psTable) - { - CPLAddXMLChild(psTree, psTable); - } - } - } - return psTree; -} - -// ******************************************************** -// Deserialize() -// ******************************************************** -STDMETHODIMP CShapefile::Deserialize(VARIANT_BOOL LoadSelection, BSTR newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - - CString s = OLE2CA(newVal); - CPLXMLNode* node = CPLParseXMLString(s.GetString()); - if (node) - { - CPLXMLNode* nodeSf = CPLGetXMLNode(node, "=ShapefileClass"); - if (nodeSf) - { - this->DeserializeCore(VARIANT_TRUE, nodeSf); - } - CPLDestroyXMLNode(node); - } - return S_OK; -} - -// ******************************************************** -// DeserializeCore() -// ******************************************************** -bool CShapefile::DeserializeCore(VARIANT_BOOL LoadSelection, CPLXMLNode* node) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - - if (!node) - return false; - - CString s = CPLGetXMLValue(node, "VisibilityExpression", nullptr); - SysFreeString(_expression); - _expression = A2BSTR(s); - - s = CPLGetXMLValue(node, "UseQTree", nullptr); - _useQTree = s != "" ? (BOOL)atoi(s.GetString()) : FALSE; - - s = CPLGetXMLValue(node, "CollisionMode", nullptr); - _collisionMode = s != "" ? (tkCollisionMode)atoi(s.GetString()) : LocalList; - - s = CPLGetXMLValue(node, "SelectionAppearance", nullptr); - _selectionAppearance = s != "" ? (tkSelectionAppearance)atoi(s.GetString()) : saSelectionColor; - - s = CPLGetXMLValue(node, "SelectionColor", nullptr); - _selectionColor = s != "" ? (OLE_COLOR)atoi(s.GetString()) : RGB(255, 255, 0); - - s = CPLGetXMLValue(node, "SelectionTransparency", nullptr); - _selectionTransparency = s != "" ? (unsigned char)atoi(s.GetString()) : 180; - - s = CPLGetXMLValue(node, "MinDrawingSize", nullptr); - _minDrawingSize = s != "" ? atoi(s.GetString()) : 1; - - s = CPLGetXMLValue(node, "SortField", nullptr); - const CComBSTR bstrSortField = A2W(s); - this->put_SortField(bstrSortField); - - s = CPLGetXMLValue(node, "SortAscending", nullptr); - const VARIANT_BOOL sortAsc = s != "" ? (VARIANT_BOOL)atoi(s.GetString()) : VARIANT_FALSE; - this->put_SortAscending(sortAsc); - - if (_sourceType == sstInMemory) - { - s = CPLGetXMLValue(node, "ShpType", nullptr); - if (s != "") - { - _shpfiletype = (ShpfileType)atoi(s.GetString()); - } - } - - // drawing options - CPLXMLNode* psChild = CPLGetXMLNode(node, "DefaultDrawingOptions"); - if (psChild) - { - ((CShapeDrawingOptions*)_defaultDrawOpt)->DeserializeCore(psChild); - } - - if (_selectionAppearance == saDrawingOptions) - { - psChild = CPLGetXMLNode(node, "SelectionDrawingOptions"); - if (psChild) - { - ((CShapeDrawingOptions*)_selectDrawOpt)->DeserializeCore(psChild); - } - } - - // Categories - psChild = CPLGetXMLNode(node, "ShapefileCategoriesClass"); - if (psChild) - { - ((CShapefileCategories*)_categories)->DeserializeCore(psChild, false); - } - - CPLXMLNode* nodeCats = CPLGetXMLNode(node, "CategoryIndices"); - bool needsApplyExpression = true; - if (nodeCats) - { - CString indices = CPLGetXMLValue(nodeCats, "=CategoryIndices", ""); - if (indices.GetLength() > 0) - { - s = CPLGetXMLValue(nodeCats, "Count", "0"); - const long savedCount = atoi(s); - int foundCount = 0; - char* buffer = indices.GetBuffer(); - for (int i = 0; i < indices.GetLength(); i++) - { - if (buffer[i] == ',') - { - foundCount++; - } - } - - if (foundCount == savedCount && foundCount == _shapeData.size()) - { - const int size = _shapeData.size(); - int pos = 0, count = 0; - CString ct = indices.Tokenize(",", pos); - while (ct.GetLength() != 0 && count < size) - { - _shapeData[count]->category = atoi(ct); - ct = indices.Tokenize(",", pos); - count++; - }; - bool needsApplyExpression = false; - } - } - } - - // If no indeces or invalid indeces, re-apply: - if (needsApplyExpression) - { - ((CShapefileCategories*)_categories)->ApplyExpressions(); - } - - // Labels - psChild = CPLGetXMLNode(node, "LabelsClass"); - if (psChild) - { - ((CLabels*)_labels)->DeserializeCore(psChild); - } - - // Charts - psChild = CPLGetXMLNode(node, "ChartsClass"); - if (psChild) - { - ((CCharts*)_charts)->DeserializeCore(psChild); - } - - // selection - CPLXMLNode* nodeSelection = CPLGetXMLNode(node, "Selection"); - if (nodeSelection && LoadSelection) - { - this->SelectNone(); - - s = CPLGetXMLValue(nodeSelection, "TotalCount", "0"); - const long count = atoi(s); - s = CPLGetXMLValue(nodeSelection, "=Selection", ""); - if (s.GetLength() == count && s.GetLength() == _shapeData.size()) - { - char* selection = s.GetBuffer(); - for (unsigned int i = 0; i < _shapeData.size(); i++) - { - if (selection[i] == '1') - { - _shapeData[i]->selected(true); - } - } - } - } - - - // table - if (_table) - { - psChild = CPLGetXMLNode(node, "TableClass"); - if (psChild) - { - ((CTableClass*)_table)->DeserializeCore(psChild); - } - } - return true; -} -#pragma endregion - - -#pragma region Projection -// ***************************************************************** -// get_Projection() -// ***************************************************************** -STDMETHODIMP CShapefile::get_Projection(BSTR* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - _geoProjection->ExportToProj4(pVal); - return S_OK; -} - -// ***************************************************************** -// put_Projection() -// ***************************************************************** -STDMETHODIMP CShapefile::put_Projection(BSTR proj4Projection) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - - VARIANT_BOOL vbretval; - _geoProjection->ImportFromProj4(proj4Projection, &vbretval); - if (vbretval) - { - const CComBSTR bstrFilename(_prjfileName); - _geoProjection->WriteToFileEx(bstrFilename, VARIANT_TRUE, &vbretval); - } - return S_OK; -} - -// ***************************************************************** -// get_GeoProjection() -// ***************************************************************** -STDMETHODIMP CShapefile::get_GeoProjection(IGeoProjection** retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (_geoProjection) - _geoProjection->AddRef(); - - *retVal = _geoProjection; - return S_OK; -} - -// ***************************************************************** -// put_GeoProjection() -// ***************************************************************** -STDMETHODIMP CShapefile::put_GeoProjection(IGeoProjection* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - ComHelper::SetRef((IDispatch*)pVal, (IDispatch**)&_geoProjection, false); - if (_prjfileName.GetLength() != 0) - { - VARIANT_BOOL vbretval; - const CComBSTR bstr(_prjfileName); - _geoProjection->WriteToFileEx(bstr, VARIANT_TRUE, &vbretval); - } - return S_OK; -} - -// **************************************************************** -// get_IsGeographicProjection -// **************************************************************** -STDMETHODIMP CShapefile::get_IsGeographicProjection(VARIANT_BOOL* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - *pVal = VARIANT_FALSE; - - if (_geoProjection) - _geoProjection->get_IsGeographic(pVal); - - return S_OK; -} - -// ***************************************************************** -// Reproject() -// ***************************************************************** -STDMETHODIMP CShapefile::Reproject(IGeoProjection* newProjection, LONG* reprojectedCount, IShapefile** retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - if (!this->ReprojectCore(newProjection, reprojectedCount, retVal, false)) - *retVal = nullptr; - return S_OK; -} - -// ***************************************************************** -// ReprojectInPlace() -// ***************************************************************** -STDMETHODIMP CShapefile::ReprojectInPlace(IGeoProjection* newProjection, LONG* reprojectedCount, VARIANT_BOOL* retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (!_isEditingShapes) - { - ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); - *retVal = VARIANT_FALSE; - } - else - { - if (this->ReprojectCore(newProjection, reprojectedCount, nullptr, true)) - { - // spatial index must be deleted, as it became useful all the same - VARIANT_BOOL vb; - RemoveSpatialIndex(&vb); - - // update qtree - if (_useQTree) - GenerateQTree(); - - VARIANT_BOOL vbretval; - this->RefreshExtents(&vbretval); - *retVal = VARIANT_TRUE; - return S_OK; - } - *retVal = NULL; - } - return S_OK; -} - -// ***************************************************************** -// ReprojectCore() -// ***************************************************************** -bool CShapefile::ReprojectCore(IGeoProjection* newProjection, LONG* reprojectedCount, IShapefile** retVal, - bool reprojectInPlace) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - // ------------------------------------------------------ - // Validation - // ------------------------------------------------------ - if (!newProjection) - { - ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); - return false; - } - - VARIANT_BOOL isEmpty1, isEmpty2; - newProjection->get_IsEmpty(&isEmpty1); - _geoProjection->get_IsEmpty(&isEmpty2); - if (isEmpty1 || isEmpty2) - { - ErrorMessage(tkPROJECTION_NOT_INITIALIZED); - return false; - } - - if (!ValidateInput(this, "Reproject/ReprojectInPlace", "this", VARIANT_FALSE)) - return false; - - m_globalSettings.gdalErrorMessage = ""; - OGRSpatialReference* projSource = ((CGeoProjection*)_geoProjection)->get_SpatialReference(); - OGRSpatialReference* projTarget = ((CGeoProjection*)newProjection)->get_SpatialReference(); - - OGRCoordinateTransformation* transf = OGRCreateCoordinateTransformation(projSource, projTarget); - if (!transf) - { - m_globalSettings.gdalErrorMessage = CPLGetLastErrorMsg(); - ErrorMessage(tkFAILED_TO_REPROJECT); - return false; - } - - // ------------------------------------------------------ - // Creating output - // ------------------------------------------------------ - if (!reprojectInPlace) - this->Clone(retVal); - - // ------------------------------------------------------ - // Processing - // ------------------------------------------------------ - CComVariant var; - const long numShapes = _shapeData.size(); - long newIndex = 0; - - long numFields, percent = 0; - this->get_NumFields(&numFields); - - VARIANT_BOOL vb = VARIANT_FALSE; - *reprojectedCount = 0; - - for (long i = 0; i < numShapes; i++) - { - CallbackHelper::Progress(_globalCallback, i, numShapes, "Reprojecting...", _key, percent); - - IShape* shp = nullptr; - this->GetValidatedShape(i, &shp); - if (!shp) continue; - - if (!reprojectInPlace) - { - IShape* shpNew = nullptr; - shp->Clone(&shpNew); - shp->Release(); - shp = shpNew; - } - - if (shp) - { - long numPoints; - shp->get_NumPoints(&numPoints); - - if (numPoints > 0) - { - auto* x = new double[numPoints]; - auto* y = new double[numPoints]; - - // extracting coordinates - for (long j = 0; j < numPoints; j++) - { - shp->get_XY(j, x + j, y + j, &vb); - } - - // will work faster after embedding to the CShape class - const BOOL res = transf->Transform(numPoints, x, y); - if (!res) - { - // save error message and continue - if (m_globalSettings.gdalErrorMessage == "") - m_globalSettings.gdalErrorMessage = CPLGetLastErrorMsg(); - } - else - { - // saving updated coordinates - for (long j = 0; j < numPoints; j++) - { - shp->put_XY(j, x[j], y[j], &vb); - } - - if (!reprojectInPlace) - { - // get next available index - (*retVal)->get_NumShapes(&newIndex); - // insert Shape into target at new index - (*retVal)->EditInsertShape(shp, &newIndex, &vb); - - // copy attributes - for (long j = 0; j < numFields; j++) - { - // get cell value at source index i - this->get_CellValue(j, i, &var); - // set cell value into target at new index - (*retVal)->EditCellValue(j, newIndex, var, &vb); - } - } - // - (*reprojectedCount)++; - } - delete[] x; - delete[] y; - } - shp->Release(); - } - } - - if (transf) - { - OGRCoordinateTransformation::DestroyCT(transf); - transf = nullptr; - } - - // function result will be based on successful projection setting - vb = VARIANT_FALSE; - // if at least some rows were reprojected... - if (*reprojectedCount > 0) - { - // setting new projection - if (reprojectInPlace) - { - // vb result will be used to determine overall success - _geoProjection->CopyFrom(newProjection, &vb); - } - else - { - IGeoProjection* proj = nullptr; - (*retVal)->get_GeoProjection(&proj); - if (proj) - { - // vb result will be used to determine overall success - proj->CopyFrom(newProjection, &vb); - proj->Release(); - } - } - } - - // inserted shapes were marked as modified, correct this - if (reprojectInPlace) - ShapefileHelper::ClearShapefileModifiedFlag(this); - else - ShapefileHelper::ClearShapefileModifiedFlag(*retVal); - - // -------------------------------------- - // Output validation - // -------------------------------------- - CallbackHelper::ProgressCompleted(_globalCallback, _key); - - if (!reprojectInPlace) - { - this->ValidateOutput(retVal, "Reproject/ReprojectInPlace", "Shapefile", false); - } - else - { - this->ValidateOutput(this, "Reproject/ReprojectInPlace", "Shapefile", false); - } - - // it's critical to set correct projection, so false will be returned if it wasn't done - return vb != 0; -} -#pragma endregion - -// ***************************************************************** -// FixUpShapes() -// ***************************************************************** -STDMETHODIMP CShapefile::FixUpShapes(IShapefile** retVal, VARIANT_BOOL* fixed) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - // MWGIS-90: default to all shapes: - FixUpShapes2(VARIANT_FALSE, retVal, fixed); - - return S_OK; -} - -// ********************************************************* -// FixUpShapes2() -// ********************************************************* -STDMETHODIMP CShapefile::FixUpShapes2(VARIANT_BOOL SelectedOnly, IShapefile** result, VARIANT_BOOL* fixed) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - *fixed = VARIANT_FALSE; - - if (*result == nullptr) - { - Clone(result); - } - - *fixed = FixupShapesCore(SelectedOnly, *result); - - return S_OK; -} - -// ********************************************************* -// FixupShapesCore() -// ********************************************************* -VARIANT_BOOL CShapefile::FixupShapesCore(VARIANT_BOOL selectedOnly, IShapefile* result) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (!result) return VARIANT_FALSE; - - tkUnitsOfMeasure units; - _geoProjection->get_LinearUnits(&units); - - long numFields; - this->get_NumFields(&numFields); - - long percent = 0; - const int numShapes = _shapeData.size(); - // VARIANT_BOOL fixed = VARIANT_TRUE; - - for (int i = 0; i < numShapes; i++) - { - CallbackHelper::Progress(_globalCallback, i, numShapes, "Fixing...", _key, percent); - - if (!ShapeAvailable(i, selectedOnly)) - continue; - - IShape* shp = nullptr; - get_Shape(i, &shp); - if (!shp) - { - continue; - } - - IShape* shpNew = nullptr; - shp->FixUp2(units, &shpNew); - shp->Release(); - - // failed to fix the shape? skip it. - if (!shpNew) - { - CString s; - s.Format("Failed to fix shape: %d", i); - CallbackHelper::ErrorMsg("Shapefile", nullptr, "", s); - continue; - } - - long shapeIndex = 0; - result->get_NumShapes(&shapeIndex); - - VARIANT_BOOL vbretval = VARIANT_FALSE; - result->EditInsertShape(shpNew, &shapeIndex, &vbretval); - shpNew->Release(); - - if (vbretval) - { - // TODO: extract, it's definitely used in other methods as well - CComVariant var; - for (int iFld = 0; iFld < numFields; iFld++) - { - get_CellValue(iFld, i, &var); - result->EditCellValue(iFld, shapeIndex, var, &vbretval); - } - } - } - - CallbackHelper::ProgressCompleted(_globalCallback, _key); - - return VARIANT_TRUE; -} - -// ********************************************************* -// GetRelatedShapes() -// ********************************************************* -STDMETHODIMP CShapefile::GetRelatedShapes(long referenceIndex, tkSpatialRelation relation, VARIANT* resultArray, - VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - if (referenceIndex < 0 || referenceIndex > (long)_shapeData.size()) - { - this->ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - return S_OK; - } - - IShape* shp = nullptr; - this->get_Shape(referenceIndex, &shp); - if (shp) - { - this->GetRelatedShapeCore(shp, referenceIndex, relation, resultArray, retval); - shp->Release(); - } - return S_OK; -} - -// ********************************************************* -// GetRelatedShapes2() -// ********************************************************* -STDMETHODIMP CShapefile::GetRelatedShapes2(IShape* referenceShape, tkSpatialRelation relation, VARIANT* resultArray, - VARIANT_BOOL* retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - if (!referenceShape) - { - this->ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); - return S_OK; - } - - this->GetRelatedShapeCore(referenceShape, -1, relation, resultArray, retval); - return S_OK; -} - -// ********************************************************* -// GetRelatedShapeCore() -// ********************************************************* -void CShapefile::GetRelatedShapeCore(IShape* referenceShape, long referenceIndex, tkSpatialRelation relation, - VARIANT* resultArray, VARIANT_BOOL* retval) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (relation == srDisjoint) - { - // TODO: implement - ErrorMessage(tkMETHOD_NOT_IMPLEMENTED); - return; - } - - // rather than generate geometries for all shapes, - // only generate for those within qtree extent (see below) - //this->ReadGeosGeometries(VARIANT_FALSE); - - // turns on the quad tree - VARIANT_BOOL useQTree = VARIANT_FALSE; - this->get_UseQTree(&useQTree); - if (!useQTree) this->put_UseQTree(VARIANT_TRUE); - - double xMin, xMax, yMin, yMax; - if (((CShape*)referenceShape)->get_ExtentsXY(xMin, yMin, xMax, yMax)) - { - const QTreeExtent query(xMin, xMax, yMax, yMin); - std::vector shapes = this->_qtree->GetNodes(query); - std::vector arr; - - // generate GEOS geometries only for shapes within qtree extent - for (size_t i = 0; i < shapes.size(); i++) - // minimize work by 'select'ing necessary shapes - this->put_ShapeSelected(shapes[i], VARIANT_TRUE); - // now generate only for 'select'ed shapes - this->ReadGeosGeometries(VARIANT_TRUE); - // don't leave shapes 'select'ed - for (size_t i = 0; i < shapes.size(); i++) - this->put_ShapeSelected(shapes[i], VARIANT_FALSE); - - GEOSGeom geomBase; - if (referenceIndex > 0) - { - geomBase = _shapeData[referenceIndex]->geosGeom; - } - else - { - geomBase = GeosConverter::ShapeToGeom(referenceShape); - } - - if (geomBase) - { - for (size_t i = 0; i < shapes.size(); i++) - { - if (i == referenceIndex) - continue; // it doesn't make sense to compare the shape with itself - - // ReSharper disable once CppLocalVariableMayBeConst - GEOSGeom geom = _shapeData[shapes[i]]->geosGeom; - if (geom != nullptr) - { - char res = 0; - switch (relation) - { - case srContains: res = GeosHelper::Contains(geomBase, geom); - break; - case srCrosses: res = GeosHelper::Crosses(geomBase, geom); - break; - case srEquals: res = GeosHelper::Equals(geomBase, geom); - break; - case srIntersects: res = GeosHelper::Intersects(geomBase, geom); - break; - case srOverlaps: res = GeosHelper::Overlaps(geomBase, geom); - break; - case srTouches: res = GeosHelper::Touches(geomBase, geom); - break; - case srWithin: res = GeosHelper::Within(geomBase, geom); - break; - case srDisjoint: break; - default: ; - } - if (res) - { - arr.push_back(shapes[i]); - } - } - } - - if (referenceIndex == -1) - GeosHelper::DestroyGeometry(geomBase); - // the geometry was created in this function so it must be destroyed - } - - *retval = Templates::Vector2SafeArray(&arr, VT_I4, resultArray); - } - - // Don't clear the list here as function may be called in a loop - //this->ClearCachedGeometries(); -} - -// *************************************************** -// get_Identifiable -// *************************************************** -STDMETHODIMP CShapefile::get_Identifiable(VARIANT_BOOL* retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retVal = _hotTracking; - return S_OK; -} - -STDMETHODIMP CShapefile::put_Identifiable(VARIANT_BOOL newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - _hotTracking = newVal; - return S_OK; -} - -// ***************************************************************** -// EditAddField() -// ***************************************************************** -STDMETHODIMP CShapefile::EditAddField(BSTR name, FieldType type, int precision, int width, long* fieldIndex) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (!this->_table) - { - this->ErrorMessage(tkDBF_FILE_DOES_NOT_EXIST); - } - else - { - _table->EditAddField(name, type, precision, width, fieldIndex); - } - return S_OK; -} - -// ***************************************************************** -// EditAddShape() -// ***************************************************************** -STDMETHODIMP CShapefile::EditAddShape(IShape* shape, long* shapeIndex) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - VARIANT_BOOL retval; - *shapeIndex = _shapeData.size(); - - EditInsertShape(shape, shapeIndex, &retval); - - if (retval == VARIANT_FALSE) - *shapeIndex = -1; - - return S_OK; -} - -// ***************************************************************** -// GetClosestVertex() -// ***************************************************************** -STDMETHODIMP CShapefile::GetClosestVertex(double x, double y, double maxDistance, - long* shapeIndex, long* pointIndex, double* distance, VARIANT_BOOL* retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - *retVal = VARIANT_FALSE; - *shapeIndex = -1; - *pointIndex = -1; - - bool result = false; - if (maxDistance <= 0.0) - { - // search through all shapefile - std::vector ids; - for (size_t i = 0; i < _shapeData.size(); i++) - { - ids.push_back(i); - } - result = ShapefileHelper::GetClosestPoint(this, x, y, maxDistance, ids, shapeIndex, pointIndex, *distance); - } - else - { - std::vector ids; - Extent box(x - maxDistance, x + maxDistance, y - maxDistance, y + maxDistance); - if (this->SelectShapesCore(box, 0.0, SelectMode::INTERSECTION, ids, false)) - { - result = ShapefileHelper::GetClosestPoint(this, x, y, maxDistance, ids, shapeIndex, pointIndex, *distance); - } - } - *retVal = result ? VARIANT_TRUE : VARIANT_FALSE; - return S_OK; -} - -// ***************************************************************** -// GetClosestSnapPosition() -// ***************************************************************** -STDMETHODIMP CShapefile::GetClosestSnapPosition(double x, double y, double maxDistance, - long* shapeIndex, double* fx, double* fy, double* distance, VARIANT_BOOL* retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - *retVal = VARIANT_FALSE; - *shapeIndex = -1; - - bool result = false; - if (maxDistance <= 0.0) - { - // search through all shapefile - std::vector ids; - for (size_t i = 0; i < _shapeData.size(); i++) - { - ids.push_back(i); - } - result = ShapefileHelper::GetClosestSnapPosition(this, x, y, maxDistance, ids, shapeIndex, *fx, *fy, *distance); - } - else - { - std::vector ids; - Extent box(x - maxDistance, x + maxDistance, y - maxDistance, y + maxDistance); - if (this->SelectShapesCore(box, 0.0, SelectMode::INTERSECTION, ids, false)) - { - result = ShapefileHelper::GetClosestSnapPosition(this, x, y, maxDistance, ids, shapeIndex, *fx, *fy, *distance); - } - } - *retVal = result ? VARIANT_TRUE : VARIANT_FALSE; - return S_OK; -} - -// ***************************************************************** -// HasInvalidShapes() -// ***************************************************************** -STDMETHODIMP CShapefile::HasInvalidShapes(VARIANT_BOOL* result) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *result = VARIANT_FALSE; - const int numShapes = _shapeData.size(); - - for (int i = 0; i < numShapes; i++) - { - IShape* shp = nullptr; - this->get_Shape(i, &shp); - - if (!shp) - { - *result = VARIANT_TRUE; - break; - } - - VARIANT_BOOL retval = VARIANT_TRUE; - shp->get_IsValid(&retval); - shp->Release(); - if (retval == VARIANT_FALSE) - { - *result = VARIANT_TRUE; - break; - } - } - return S_OK; -} - -// ***************************************************************** -// get_UndoList() -// ***************************************************************** -STDMETHODIMP CShapefile::get_UndoList(IUndoList** pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - if (_undoList) - _undoList->AddRef(); - *pVal = _undoList; - return S_OK; -} - -// ***************************************************************** -// Snappable() -// ***************************************************************** -STDMETHODIMP CShapefile::get_Snappable(VARIANT_BOOL* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _snappable; - return S_OK; -} - -STDMETHODIMP CShapefile::put_Snappable(VARIANT_BOOL newVal) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - _snappable = newVal; - return S_OK; -} - -// ***************************************************************** -// ShapefileType2D() -// ***************************************************************** -STDMETHODIMP CShapefile::get_ShapefileType2D(ShpfileType* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = ShapeUtility::Convert2D(_shpfiletype); - return S_OK; -} - -// ***************************************************************** -// FieldIndexByName() -// ***************************************************************** -STDMETHODIMP CShapefile::get_FieldIndexByName(BSTR FieldName, LONG* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - _table->get_FieldIndexByName(FieldName, pVal); - return S_OK; -} - -// *************************************************** -// get_Selectable -// *************************************************** -STDMETHODIMP CShapefile::get_Selectable(VARIANT_BOOL* retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retVal = _selectable; - return S_OK; -} - -STDMETHODIMP CShapefile::put_Selectable(VARIANT_BOOL newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - _selectable = newVal; - return S_OK; -} - -// ***************************************************************** -// Move() -// ***************************************************************** -STDMETHODIMP CShapefile::Move(DOUBLE xProjOffset, DOUBLE yProjOffset, VARIANT_BOOL* retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retVal = VARIANT_FALSE; - if (_sourceType != sstInMemory) - { - ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); - return S_OK; - } - long numShapes; - get_NumShapes(&numShapes); - for (long i = 0; i < numShapes; i++) - { - CComPtr shp = nullptr; - get_Shape(i, &shp); - if (shp) - { - shp->Move(xProjOffset, yProjOffset); - } - } - *retVal = VARIANT_TRUE; - return S_OK; -} - -// ***************************************************************** -// get_ShapeRendered() -// ***************************************************************** -STDMETHODIMP CShapefile::get_ShapeRendered(LONG ShapeIndex, VARIANT_BOOL* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - *pVal = VARIANT_FALSE; - if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - *pVal = _shapeData[ShapeIndex]->wasRendered() ? VARIANT_TRUE : VARIANT_FALSE; - } - return S_OK; -} - -// ***************************************************************** -// MarkUndrawn() -// ***************************************************************** -void CShapefile::MarkUndrawn() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - for (auto& i : _shapeData) - { - i->wasRendered(false); - } -} - -// ************************************************************* -// SortField() -// ************************************************************* -STDMETHODIMP CShapefile::get_SortField(BSTR* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - USES_CONVERSION; - *pVal = OLE2BSTR(_sortField); - - return S_OK; -} - -STDMETHODIMP CShapefile::put_SortField(BSTR newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - SysFreeString(_sortField); - USES_CONVERSION; - _sortField = OLE2BSTR(newVal); - - _sortingChanged = true; - - if (_labels) - { - _labels->UpdateSizeField(); - } - - return S_OK; -} - -// ************************************************************* -// SortAscending() -// ************************************************************* -STDMETHODIMP CShapefile::get_SortAscending(VARIANT_BOOL* pVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - *pVal = _sortAscending; - - return S_OK; -} - -STDMETHODIMP CShapefile::put_SortAscending(VARIANT_BOOL newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - _sortAscending = newVal; - _sortingChanged = true; - - return S_OK; -} - -// ************************************************************* -// UpdateSorting() -// ************************************************************* -STDMETHODIMP CShapefile::UpdateSortField() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - // this will trigger rereading of the table on next redraw - _sortingChanged = true; - - return S_OK; -} - -// ************************************************************* -// GetSorting() -// ************************************************************* -bool CShapefile::GetSorting(vector** indices) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - *indices = nullptr; - - if (!_sortingChanged) - { - *indices = &_sorting; - return true; - } - - long fieldIndex; - get_FieldIndexByName(_sortField, &fieldIndex); - - if (fieldIndex == -1) - { - return false; - } - - if (!_table) - { - return false; - } - - _sortingChanged = false; - - if (((CTableClass*)_table)->GetSorting(fieldIndex, _sorting)) - { - if (!_sortAscending) - { - std::reverse(_sorting.begin(), _sorting.end()); - } - - *indices = &_sorting; - return true; - } - CallbackHelper::ErrorMsg("Failed to sort labels"); - - return false; -} +//******************************************************************************************************** +//File name: Shapefile.cpp +//Description: Implementation of the CShapefile +//******************************************************************************************************** +//The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); +//you may not use this file except in compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +//ANY KIND, either express or implied. See the License for the specific language governing rights and +//limitations under the License. +// +//The Original Code is MapWindow Open Source. +// +//The Initial Developer of this version of the Original Code is Daniel P. Ames using portions created by +//Utah State University and the Idaho National Engineering and Environmental Lab that were released as +//public domain in March 2004. +//******************************************************************************************************** +// +//Contributor(s): (Open source contributors should list themselves and their modifications here). +// ------------------------------------------------------------------------------------------------------- +// Paul Meems August 2018: Modernized the code as suggested by CLang and ReSharper + +#include "StdAfx.h" +#include +#include "Shapefile.h" +#include "Labels.h" +#include "Charts.h" +#include "GeoProjection.h" +#include "Templates.h" +#include +#include "ShapefileCategories.h" +#include "Shape.h" +#include "GeosConverter.h" +#include "ShapefileHelper.h" +#include "LabelsHelper.h" +#include "ShapeStyleHelper.h" +#include "TableClass.h" + +#ifdef _DEBUG + #define new DEBUG_NEW + #undef THIS_FILE + static char THIS_FILE[] = __FILE__; +#endif + +CShapefile::CShapefile() +{ + _pUnkMarshaler = nullptr; + + _sortingChanged = true; + _sortAscending = VARIANT_FALSE; + _sortField = SysAllocString(L""); + + _appendStartShapeCount = -1; + _appendMode = VARIANT_FALSE; + _snappable = VARIANT_TRUE; + _interactiveEditing = VARIANT_FALSE; + _hotTracking = VARIANT_TRUE; + _selectable = VARIANT_FALSE; + _geosGeometriesRead = false; + _stopExecution = nullptr; + + _selectionTransparency = 180; + _selectionAppearance = saSelectionColor; + _selectionColor = RGB(255, 255, 0); + _collisionMode = tkCollisionMode::LocalList; + + _geometryEngine = m_globalSettings.geometryEngine; + + _sourceType = sstUninitialized; + + _writing = false; + _reading = false; + + _isEditingShapes = FALSE; + _fastMode = m_globalSettings.shapefileFastMode ? TRUE : FALSE; + _minDrawingSize = 1; + _volatile = false; + + _useSpatialIndex = TRUE; + _hasSpatialIndex = FALSE; + _spatialIndexLoaded = FALSE; + _spatialIndexMaxAreaPercent = 0.5; + _spatialIndexNodeCapacity = 100; + + //Neio 20090721 + _useQTree = FALSE; + _cacheExtents = FALSE; + _qtree = nullptr; + _tempTree = nullptr; + + _shpfile = nullptr; + _shxfile = nullptr; + + _shpfiletype = SHP_NULLSHAPE; + _nextShapeHandle = 0; + + _minX = 0.0; + _minY = 0.0; + _minZ = 0.0; + _maxX = 0.0; + _maxY = 0.0; + _maxZ = 0.0; + _minM = 0.0; + _maxM = 0.0; + + _key = SysAllocString(L""); + _expression = SysAllocString(L""); + _globalCallback = nullptr; + _lastErrorCode = tkNO_ERROR; + _table = nullptr; + + // creation of children classes + _selectDrawOpt = nullptr; + _defaultDrawOpt = nullptr; + _labels = nullptr; + _categories = nullptr; + _charts = nullptr; + _geoProjection = nullptr; + + ComHelper::CreateInstance(idShapeValidationInfo, (IDispatch**)&_inputValidation); + ComHelper::CreateInstance(idShapeValidationInfo, (IDispatch**)&_outputValidation); + + CoCreateInstance(CLSID_ShapeDrawingOptions, nullptr, CLSCTX_INPROC_SERVER, IID_IShapeDrawingOptions, + (void**)&_selectDrawOpt); + CoCreateInstance(CLSID_ShapeDrawingOptions, nullptr, CLSCTX_INPROC_SERVER, IID_IShapeDrawingOptions, + (void**)&_defaultDrawOpt); + CoCreateInstance(CLSID_ShapefileCategories, nullptr, CLSCTX_INPROC_SERVER, IID_IShapefileCategories, + (void**)&_categories); + CoCreateInstance(CLSID_Labels, nullptr, CLSCTX_INPROC_SERVER, IID_ILabels, (void**)&_labels); + CoCreateInstance(CLSID_Charts, nullptr, CLSCTX_INPROC_SERVER, IID_ICharts, (void**)&_charts); + CoCreateInstance(CLSID_GeoProjection, nullptr, CLSCTX_INPROC_SERVER, IID_IGeoProjection, (void**)&_geoProjection); + + this->put_ReferenceToLabels(); + this->put_ReferenceToCategories(); + this->put_ReferenceToCharts(); + + ComHelper::CreateInstance(idUndoList, (IDispatch**)&_undoList); + + gReferenceCounter.AddRef(tkInterface::idShapefile); +} + +CShapefile::~CShapefile() +{ + VARIANT_BOOL vbretval; + this->CShapefile::Close(&vbretval); + + SysFreeString(_key); + SysFreeString(_expression); + SysFreeString(_sortField); + + if (_selectDrawOpt != nullptr) + _selectDrawOpt->Release(); + + if (_defaultDrawOpt != nullptr) + _defaultDrawOpt->Release(); + + if (_labels != nullptr) + { + put_ReferenceToLabels(true); // labels class maybe referenced by client and won't be deleted as a result + _labels->Release(); // therefore we must clear the reference to the parent as it will be invalid + } + + if (_categories != nullptr) + { + put_ReferenceToCategories(true); + _categories->Release(); + } + + if (_charts != nullptr) + { + put_ReferenceToCharts(true); + _charts->Release(); + } + + if (_stopExecution) + _stopExecution->Release(); + + if (_geoProjection) + _geoProjection->Release(); + + if (_undoList) + { + _undoList->Release(); + } + gReferenceCounter.Release(tkInterface::idShapefile); +} + +std::vector* CShapefile::get_ShapeVector() +{ + return &_shapeData; +} + +IShapeWrapper* CShapefile::get_ShapeWrapper(int ShapeIndex) +{ + return ((CShape*)_shapeData[ShapeIndex]->shape)->get_ShapeWrapper(); +} + +IShapeData* CShapefile::get_ShapeRenderingData(int ShapeIndex) +{ + return _shapeData[ShapeIndex]->get_RenderingData(); +} + +void CShapefile::put_ShapeRenderingData(int ShapeIndex, CShapeData* data) +{ + return _shapeData[ShapeIndex]->put_RenderingData(data); +} + +void CShapefile::SetValidationInfo(IShapeValidationInfo* info, tkShapeValidationType validationType) +{ + ComHelper::SetRef(info, + (IDispatch**)&(validationType == svtInput ? _inputValidation : _outputValidation), true); +} + +#pragma region Properties + +// ************************************************************ +// get_EditingShapes() +// ************************************************************ +STDMETHODIMP CShapefile::get_EditingShapes(VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *pVal = _isEditingShapes ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; +} + +// ************************************************************ +// get_LastErrorCode() +// ************************************************************ +STDMETHODIMP CShapefile::get_LastErrorCode(long* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *pVal = _lastErrorCode; + _lastErrorCode = tkNO_ERROR; + return S_OK; +} + +// ************************************************************ +// get_CdlgFilter() +// ************************************************************ +STDMETHODIMP CShapefile::get_CdlgFilter(BSTR* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + USES_CONVERSION; + *pVal = A2BSTR("ESRI Shapefiles (*.shp)|*.shp"); + return S_OK; +} + +// ************************************************************ +// LastInputValidation +// ************************************************************ +STDMETHODIMP CShapefile::get_LastInputValidation(IShapeValidationInfo** retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + if (_inputValidation) + _inputValidation->AddRef(); + *retVal = _inputValidation; + return S_OK; +} + +// ************************************************************ +// LastOutputValidation +// ************************************************************ +STDMETHODIMP CShapefile::get_LastOutputValidation(IShapeValidationInfo** retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + if (_outputValidation) + _outputValidation->AddRef(); + *retVal = _outputValidation; + return S_OK; +} + +// ************************************************************ +// get/put_GlobalCallback() +// ************************************************************ +STDMETHODIMP CShapefile::get_GlobalCallback(ICallback** pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + *pVal = _globalCallback; + if (_globalCallback != nullptr) + _globalCallback->AddRef(); + return S_OK; +} + +STDMETHODIMP CShapefile::put_GlobalCallback(ICallback* newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + ComHelper::SetRef(newVal, (IDispatch**)&_globalCallback); + if (_table != nullptr) + _table->put_GlobalCallback(newVal); + + return S_OK; +} + +// ************************************************************ +// StopExecution +// ************************************************************ +STDMETHODIMP CShapefile::put_StopExecution(IStopExecution* stopper) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + ComHelper::SetRef((IDispatch*)stopper, (IDispatch**)&_stopExecution, true); + return S_OK; +} + +// ************************************************************ +// get/put_Key() +// ************************************************************ +STDMETHODIMP CShapefile::get_Key(BSTR* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + USES_CONVERSION; + *pVal = OLE2BSTR(_key); + return S_OK; +} + +STDMETHODIMP CShapefile::put_Key(BSTR newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + SysFreeString(_key); + _key = OLE2BSTR(newVal); + return S_OK; +} + +// ************************************************************ +// get/put_VisibilityExpression +// ************************************************************ +STDMETHODIMP CShapefile::get_VisibilityExpression(BSTR* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + USES_CONVERSION; + *pVal = OLE2BSTR(_expression); + return S_OK; +} + +STDMETHODIMP CShapefile::put_VisibilityExpression(BSTR newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + SysFreeString(_expression); + _expression = OLE2BSTR(newVal); + return S_OK; +} + +// ************************************************************ +// get/put_Volatile +// ************************************************************ +STDMETHODIMP CShapefile::get_Volatile(VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + if (_interactiveEditing) + { + *pVal = VARIANT_TRUE; + } + else + { + *pVal = _volatile ? VARIANT_TRUE : VARIANT_FALSE; + } + return S_OK; +} + +STDMETHODIMP CShapefile::put_Volatile(VARIANT_BOOL newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + _volatile = newVal == VARIANT_TRUE; + return S_OK; +} + +// ***************************************************************** +// get_NumShapes() +// ***************************************************************** +STDMETHODIMP CShapefile::get_NumShapes(long* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *pVal = _shapeData.size(); //_numShapes; + return S_OK; +} + +// ************************************************************** +// get_NumFields() +// ************************************************************** +STDMETHODIMP CShapefile::get_NumFields(long* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + if (_table != nullptr) + _table->get_NumFields(pVal); + else + { + ErrorMessage(tkFILE_NOT_OPEN); + *pVal = 0; + } + return S_OK; +} + +// ************************************************************ +// get_ShapefileType() +// ************************************************************ +STDMETHODIMP CShapefile::get_ShapefileType(ShpfileType* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *pVal = _shpfiletype; + return S_OK; +} + +// ***************************************************************** +// get_ErrorMsg() +// ***************************************************************** +STDMETHODIMP CShapefile::get_ErrorMsg(long ErrorCode, BSTR* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + USES_CONVERSION; + *pVal = A2BSTR(ErrorMsg(ErrorCode)); + return S_OK; +} + +// ***************************************************************** +// get_FileHandle() +// ***************************************************************** +STDMETHODIMP CShapefile::get_FileHandle(long* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + if (_shpfile != nullptr) + { + const int handle = _fileno(_shpfile); + *pVal = _dup(handle); + } + else + *pVal = -1; + + return S_OK; +} + +// ************************************************************** +// get_Filename() +// ************************************************************** +STDMETHODIMP CShapefile::get_Filename(BSTR* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + *pVal = W2BSTR(_shpfileName); + + return S_OK; +} + +// ************************************************************** +// ErrorMessage() +// ************************************************************** +void CShapefile::ErrorMessage(long ErrorCode) +{ + _lastErrorCode = ErrorCode; + CallbackHelper::ErrorMsg("Shapefile", _globalCallback, _key, ErrorMsg(_lastErrorCode)); +} + +void CShapefile::ErrorMessage(long ErrorCode, ICallback* cBack) +{ + _lastErrorCode = ErrorCode; + CallbackHelper::ErrorMsg("Shapefile", _globalCallback, _key, ErrorMsg(_lastErrorCode)); + if (cBack != _globalCallback) + CallbackHelper::ErrorMsg("Shapefile", cBack, _key, ErrorMsg(_lastErrorCode)); +} + +// ************************************************************ +// get_MinDrawingSize() +// ************************************************************ +STDMETHODIMP CShapefile::get_MinDrawingSize(LONG* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *pVal = _minDrawingSize; + return S_OK; +} + +STDMETHODIMP CShapefile::put_MinDrawingSize(LONG newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + _minDrawingSize = newVal; + return S_OK; +} + +// ************************************************************ +// get_SourceType() +// ************************************************************ +STDMETHODIMP CShapefile::get_SourceType(tkShapefileSourceType* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *pVal = _sourceType; + return S_OK; +} + +#pragma endregion + +#pragma region CreateAndOpen + + +// ************************************************************ +// LoadDataFrom() +// ************************************************************ +// Loads shape and DBF data from disk file into in-memory mode +STDMETHODIMP CShapefile::LoadDataFrom(BSTR ShapefileName, ICallback* cBack, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + USES_CONVERSION; + *retval = VARIANT_FALSE; + if (_sourceType != sstInMemory) + { + ErrorMessage(tkINMEMORY_SHAPEFILE_EXPECTED); + return S_OK; + } + + if (OpenCore(OLE2CA(ShapefileName), cBack)) + { + // loading data in-memory + VARIANT_BOOL vb; + _isEditingShapes = false; + StartEditingShapes(VARIANT_TRUE, cBack, &vb); + + // this will trigger loading of all DBF values into the memory + long numFields; + this->get_NumFields(&numFields); + if (numFields > 0) + { + CComVariant var; + for (size_t i = 0; i < _shapeData.size(); i++) + { + _table->get_CellValue(0, i, &var); + } + } + + // closing disk file despite the result success or failure + _shpfileName = ""; + _shxfileName = ""; + _dbffileName = ""; + + if (_shpfile != nullptr) + fclose(_shpfile); + _shpfile = nullptr; + + if (_shxfile != nullptr) + fclose(_shxfile); + _shxfile = nullptr; + + if (_table != nullptr) + ((CTableClass*)_table)->CloseUnderlyingFile(); + + *retval = vb; + } + return S_OK; +} + +// ************************************************************ +// OpenCore() +// ************************************************************ +bool CShapefile::OpenCore(CStringW tmpShpfileName, ICallback* cBack) +{ + USES_CONVERSION; + VARIANT_BOOL vbretval; + + // saving the provided names; + // from now on we must clean the class variables in case the operation won't succeed + _shpfileName = tmpShpfileName; + _shxfileName = tmpShpfileName.Left(tmpShpfileName.GetLength() - 3) + L"shx"; + _dbffileName = tmpShpfileName.Left(tmpShpfileName.GetLength() - 3) + L"dbf"; + _prjfileName = tmpShpfileName.Left(tmpShpfileName.GetLength() - 3) + L"prj"; + + // read mode + _shpfile = _wfopen(_shpfileName, L"rb"); + _shxfile = _wfopen(_shxfileName, L"rb"); + + // opening DBF + if (!_table) + { + CoCreateInstance(CLSID_Table, nullptr, CLSCTX_INPROC_SERVER, IID_ITable, (void**)&_table); + } + else + { + VARIANT_BOOL vb; + _table->Close(&vb); + } + + _table->put_GlobalCallback(_globalCallback); + ((CTableClass*)_table)->InjectShapefile(this); + + const CComBSTR bstrDbf(_dbffileName); + _table->Open(bstrDbf, cBack, &vbretval); + + if (_shpfile == nullptr) + { + ErrorMessage(tkCANT_OPEN_SHP); + this->Close(&vbretval); + } + else if (_shxfile == nullptr) + { + ErrorMessage(tkCANT_OPEN_SHX); + this->Close(&vbretval); + } + else if (vbretval == VARIANT_FALSE) + { + _table->get_LastErrorCode(&_lastErrorCode); + ErrorMessage(_lastErrorCode); + this->Close(&vbretval); + } + else + { + if (!ReadShx()) // shapefile header is read here as well + { + ErrorMessage(tkINVALID_SHX_FILE); + this->Close(&vbretval); + } + else + { + //Check for supported types + if (_shpfiletype != SHP_NULLSHAPE && + _shpfiletype != SHP_POINT && + _shpfiletype != SHP_POLYLINE && + _shpfiletype != SHP_POLYGON && + _shpfiletype != SHP_POINTZ && + _shpfiletype != SHP_POLYLINEZ && + _shpfiletype != SHP_POLYGONZ && + _shpfiletype != SHP_MULTIPOINT && + _shpfiletype != SHP_MULTIPOINTZ && + _shpfiletype != SHP_POLYLINEM && + _shpfiletype != SHP_POLYGONM && + _shpfiletype != SHP_POINTM && + _shpfiletype != SHP_MULTIPOINTM) + { + ErrorMessage(tkUNSUPPORTED_SHAPEFILE_TYPE); + this->Close(&vbretval); + } + else + { + _shapeData.reserve(_shpOffsets.size()); + for (size_t i = 0; i < _shpOffsets.size(); i++) + { + _shapeData.push_back(new ShapeRecord()); + } + return true; + } + } + } + return false; +} + +// ************************************************************ +// Open() +// ************************************************************ +STDMETHODIMP CShapefile::Open(BSTR ShapefileName, ICallback* cBack, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retval = VARIANT_FALSE; + VARIANT_BOOL vbretval; + + if (_globalCallback == nullptr && cBack != nullptr) + { + _globalCallback = cBack; + _globalCallback->AddRef(); + } + + USES_CONVERSION; + CStringW tmp_shpfileName = OLE2CW(ShapefileName); + + if (tmp_shpfileName.GetLength() == 0) + { + // better to use CreateNew directly, but this call will be preserved for backward compatibility + this->CreateNew(m_globalSettings.emptyBstr, _shpfiletype, &vbretval); + } + else if (tmp_shpfileName.GetLength() <= 3) + { + ErrorMessage(tkINVALID_FILENAME); + } + else + { + // close the opened shapefile + this->Close(&vbretval); + + if (vbretval == VARIANT_FALSE) + { + // error code in the function + return S_OK; + } + + if (OpenCore(tmp_shpfileName, cBack)) + { + _sourceType = sstDiskBased; + + // reading projection + const CComBSTR bstrPrj(_prjfileName); + _geoProjection->ReadFromFileEx(bstrPrj, VARIANT_TRUE, &vbretval); + + ShapeStyleHelper::ApplyRandomDrawingOptions(this); + LabelsHelper::UpdateLabelsPositioning(this); + *retval = VARIANT_TRUE; + } + } + return S_OK; +} + +// ********************************************************* +// CreateNew() +// ********************************************************* +STDMETHODIMP CShapefile::CreateNew(BSTR ShapefileName, ShpfileType ShapefileType, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + return this->CreateNewCore(ShapefileName, ShapefileType, true, retval); +} + +// ********************************************************* +// CreateNewCore() +// ********************************************************* +HRESULT CShapefile::CreateNewCore(BSTR ShapefileName, ShpfileType ShapefileType, bool applyRandomOptions, + VARIANT_BOOL* retval) +{ + *retval = VARIANT_FALSE; + VARIANT_BOOL vb; + + // check for supported types + if (ShapefileType != SHP_NULLSHAPE && + ShapefileType != SHP_POINT && + ShapefileType != SHP_POLYLINE && + ShapefileType != SHP_POLYGON && + ShapefileType != SHP_POINTZ && + ShapefileType != SHP_POLYLINEZ && + ShapefileType != SHP_POLYGONZ && + ShapefileType != SHP_MULTIPOINT && + ShapefileType != SHP_MULTIPOINTZ && + ShapefileType != SHP_POINTM && // MWGIS-69 + ShapefileType != SHP_POLYLINEM && + ShapefileType != SHP_POLYGONM && + ShapefileType != SHP_MULTIPOINTM) + { + ErrorMessage(tkUNSUPPORTED_SHAPEFILE_TYPE); + return S_OK; + } + + USES_CONVERSION; + CString tmp_shpfileName = OLE2CA(ShapefileName); + + // ---------------------------------------------- + // in memory shapefile (without name) + // ---------------------------------------------- + if (tmp_shpfileName.GetLength() == 0) + { + // closing the old shapefile (error code inside the function) + Close(&vb); + + if (vb == VARIANT_TRUE) + { + CoCreateInstance(CLSID_Table, nullptr, CLSCTX_INPROC_SERVER, IID_ITable, (void**)&_table); + + _table->CreateNew(m_globalSettings.emptyBstr, &vb); + + if (!vb) + { + long error; + _table->get_LastErrorCode(&error); + ErrorMessage(error); + _table->Release(); + _table = nullptr; + } + else + { + _shpfiletype = ShapefileType; + _isEditingShapes = true; + _sourceType = sstInMemory; + + if (applyRandomOptions) + { + ShapeStyleHelper::ApplyRandomDrawingOptions(this); + } + + *retval = VARIANT_TRUE; + } + } + + return S_OK; + } + + if (tmp_shpfileName.GetLength() <= 3) + { + ErrorMessage(tkINVALID_FILENAME); + return S_OK; + } + + const CString& shpName = tmp_shpfileName; + const CString shxName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "shx"; + const CString dbfName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "dbf"; + const CString prjName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "prj"; + + // new file is created, so there must not be any files with this names + if (Utility::FileExists(shpName) != FALSE) + { + ErrorMessage(tkSHP_FILE_EXISTS); + return S_OK; + } + if (Utility::FileExists(shxName) != FALSE) + { + ErrorMessage(tkSHX_FILE_EXISTS); + return S_OK; + } + if (Utility::FileExists(dbfName) != FALSE) + { + ErrorMessage(tkDBF_FILE_EXISTS); + return S_OK; + } + if (Utility::FileExists(prjName) != FALSE) + { + ErrorMessage(tkPRJ_FILE_EXISTS); + return S_OK; + } + + // closing the old shapefile (error code inside the function) + this->Close(&vb); + + if (vb == VARIANT_TRUE) + { + CoCreateInstance(CLSID_Table, nullptr, CLSCTX_INPROC_SERVER, IID_ITable, (void**)&_table); + + _table->put_GlobalCallback(_globalCallback); + + const CString newDbfName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "dbf"; + const CComBSTR bstrName(newDbfName); + _table->CreateNew(bstrName, &vb); + + if (!vb) + { + _table->get_LastErrorCode(&_lastErrorCode); + ErrorMessage(_lastErrorCode); + _table->Release(); + _table = nullptr; + } + else + { + _shpfileName = tmp_shpfileName; + _shxfileName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "shx"; + _dbffileName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "dbf"; + _prjfileName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 3) + "prj"; + + _shpfiletype = ShapefileType; + _isEditingShapes = true; + _sourceType = sstInMemory; + + if (applyRandomOptions) + { + ShapeStyleHelper::ApplyRandomDrawingOptions(this); + } + + *retval = VARIANT_TRUE; + } + } + + LabelsHelper::UpdateLabelsPositioning(this); + + return S_OK; +} + +// ********************************************************* +// CreateNewWithShapeID() +// ********************************************************* +STDMETHODIMP CShapefile::CreateNewWithShapeID(BSTR ShapefileName, ShpfileType ShapefileType, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + USES_CONVERSION; + + CreateNew(ShapefileName, ShapefileType, retval); + + if (*retval) + ShapefileHelper::InsertMwShapeIdField(this); + + return S_OK; +} + +#pragma endregion + +#pragma region SaveAndClose +// ***************************************************************** +// Close() +// ***************************************************************** +STDMETHODIMP CShapefile::Close(VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + if (_appendMode) + { + StopAppendMode(); + } + + ClearCachedGeometries(); + + if (_isEditingShapes) + { + // just stop editing shapes, if the shape is in open status + this->StopEditingShapes(VARIANT_FALSE, VARIANT_TRUE, nullptr, retval); + } + + // stop editing table in case only it have been edited + VARIANT_BOOL isEditingTable = VARIANT_FALSE; + if (_table) + { + _table->get_EditingTable(&isEditingTable); + if (isEditingTable) + { + this->StopEditingTable(VARIANT_FALSE, _globalCallback, retval); + _table->get_EditingTable(&isEditingTable); + } + } + + // removing shape data + this->ReleaseMemoryShapes(); + for (auto& i : _shapeData) + { + delete i; + } + _shapeData.clear(); + + if (_spatialIndexLoaded) + IndexSearching::unloadSpatialIndex(_spatialIndexID); + + _sourceType = sstUninitialized; + _shpfiletype = SHP_NULLSHAPE; + LabelsHelper::UpdateLabelsPositioning(this); + + _shpfileName = ""; + _shxfileName = ""; + _dbffileName = ""; + + _minX = 0.0; + _minY = 0.0; + _minZ = 0.0; + _maxX = 0.0; + _maxY = 0.0; + _maxZ = 0.0; + _minM = 0.0; + _maxM = 0.0; + + if (_inputValidation != nullptr) + { + _inputValidation->Release(); + _inputValidation = nullptr; + } + + if (_outputValidation != nullptr) + { + _outputValidation->Release(); + _outputValidation = nullptr; + } + + if (_shpfile != nullptr) fclose(_shpfile); + _shpfile = nullptr; + + if (_shxfile != nullptr) fclose(_shxfile); + _shxfile = nullptr; + + if (_table != nullptr) + { + VARIANT_BOOL vbretval; + _table->Close(&vbretval); + _table->Release(); + _table = nullptr; + } + if (_labels) + { + _labels->Clear(); + _labels->ClearCategories(); + } + if (_charts) + { + _charts->Clear(); + } + if (_categories) + { + _categories->Clear(); + } + *retval = VARIANT_TRUE; + + return S_OK; +} + +// ********************************************************** +// Dump() +// ********************************************************** +//Saves shapefile without reopening it in a new location +STDMETHODIMP CShapefile::Dump(BSTR ShapefileName, ICallback* cBack, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retval = VARIANT_FALSE; + + const bool callbackIsNull = _globalCallback == nullptr; + if (_globalCallback == nullptr && cBack != nullptr) + { + _globalCallback = cBack; + _globalCallback->AddRef(); + } + + if (_table == nullptr || _sourceType == sstUninitialized) + { + ErrorMessage(tkSHAPEFILE_UNINITIALIZED); + return S_OK; + } + + // in case someone else is writing, we leave + if (_writing) + { + ErrorMessage(tkSHP_WRITE_VIOLATION); + return S_OK; + } + + if (!this->ValidateOutput(this, "Dump", "Shapefile", false)) + return S_OK; + + USES_CONVERSION; + CString sa_shpfileName = OLE2CA(ShapefileName); + + if (sa_shpfileName.GetLength() <= 3) + { + ErrorMessage(tkINVALID_FILENAME); + } + else + { + const CString sa_shxfileName = sa_shpfileName.Left(sa_shpfileName.GetLength() - 3) + "shx"; + CString sa_dbffileName = sa_shpfileName.Left(sa_shpfileName.GetLength() - 3) + "dbf"; + + // ----------------------------------------------- + // it's not allowed to rewrite the existing files + // ----------------------------------------------- + if (Utility::FileExists(sa_shpfileName)) + { + ErrorMessage(tkSHP_FILE_EXISTS); + return S_OK; + } + if (Utility::FileExists(sa_shxfileName)) + { + ErrorMessage(tkSHX_FILE_EXISTS); + return S_OK; + } + if (Utility::FileExists(sa_dbffileName)) + { + ErrorMessage(tkDBF_FILE_EXISTS); + return S_OK; + } + + // ----------------------------------------------- + // checking in-memory shapes + // ----------------------------------------------- + if (_isEditingShapes) + { + if (VerifyMemShapes(cBack) == FALSE) + { + // error Code is set in function + return S_OK; + } + + // refresh extents + VARIANT_BOOL retVal; + this->RefreshExtents(&retVal); + } + + // ----------------------------------------------- + // opening files + // ----------------------------------------------- + FILE* shpfile = fopen(sa_shpfileName, "wb+"); + if (shpfile == nullptr) + { + ErrorMessage(tkCANT_CREATE_SHP); + return S_OK; + } + + //shx + FILE* shxfile = fopen(sa_shxfileName, "wb+"); + if (shxfile == nullptr) + { + fclose(shpfile); + ErrorMessage(tkCANT_CREATE_SHX); + return S_OK; + } + + // ------------------------------------------------ + // writing the files + // ------------------------------------------------ + this->WriteShp(shpfile, cBack); + this->WriteShx(shxfile, cBack); + + fclose(shpfile); + fclose(shxfile); + + // ------------------------------------------------ + // saving dbf table + // ------------------------------------------------ + _table->Dump(sa_dbffileName.AllocSysString(), cBack, retval); + if (*retval == FALSE) + { + _table->get_LastErrorCode(&_lastErrorCode); + return S_OK; + } + + // saving projection in new format + VARIANT_BOOL vbretval; + const CStringW prjfileName = sa_shpfileName.Left(sa_shpfileName.GetLength() - 3) + L"prj"; + const CComBSTR bstr(prjfileName); + _geoProjection->WriteToFileEx(bstr, VARIANT_TRUE, &vbretval); + + *retval = VARIANT_TRUE; + } + + // restoring callback + if (callbackIsNull) + { + _globalCallback = nullptr; + } + + return S_OK; +} + +// ********************************************************** +// SaveAs() +// ********************************************************** +// Saves shapefile to the new or the same location. Doesn't stop editing mode. +STDMETHODIMP CShapefile::SaveAs(BSTR ShapefileName, ICallback* cBack, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retval = VARIANT_FALSE; + + const bool callbackIsNull = _globalCallback == nullptr; + if (_globalCallback == nullptr && cBack != nullptr) + { + _globalCallback = cBack; + _globalCallback->AddRef(); + } + + if (_table == nullptr || _sourceType == sstUninitialized) + { + ErrorMessage(tkSHAPEFILE_UNINITIALIZED); + return S_OK; + } + + // in case someone else is writing, we leave + if (_writing) + { + ErrorMessage(tkSHP_WRITE_VIOLATION); + return S_OK; + } + + if (!this->ValidateOutput(this, "SaveAs", "Shapefile", false)) + return S_OK; + + USES_CONVERSION; + CStringW newShpName = OLE2W(ShapefileName); + + if (newShpName.GetLength() <= 3) + { + ErrorMessage(tkINVALID_FILENAME); + } + else if (!Utility::EndsWith(newShpName, L".shp")) + { + ErrorMessage(tkINVALID_FILE_EXTENSION); + } + else + { + const CStringW newShxName = newShpName.Left(newShpName.GetLength() - 3) + L"shx"; + const CStringW newDbfName = newShpName.Left(newShpName.GetLength() - 3) + L"dbf"; + + // ----------------------------------------------- + // it's not allowed to rewrite the existing files + // ----------------------------------------------- + if (Utility::FileExistsW(newShpName)) + { + ErrorMessage(tkSHP_FILE_EXISTS); + return S_OK; + } + if (Utility::FileExistsW(newShxName)) + { + ErrorMessage(tkSHX_FILE_EXISTS); + return S_OK; + } + if (Utility::FileExistsW(newDbfName)) + { + ErrorMessage(tkDBF_FILE_EXISTS); + return S_OK; + } + + // ----------------------------------------------- + // checking in-memory shapes + // ----------------------------------------------- + if (_isEditingShapes) + { + if (VerifyMemShapes(cBack) == FALSE) + { + // error Code is set in function + return S_OK; + } + + // refresh extents + VARIANT_BOOL retVal; + RefreshExtents(&retVal); + } + + // ----------------------------------------------- + // opening files + // ----------------------------------------------- + FILE* shpfile = _wfopen(newShpName, L"wb+"); + if (shpfile == nullptr) + { + ErrorMessage(tkCANT_CREATE_SHP); + return S_OK; + } + + //shx + FILE* shxfile = _wfopen(newShxName, L"wb+"); + if (shxfile == nullptr) + { + fclose(shpfile); + ErrorMessage(tkCANT_CREATE_SHX); + return S_OK; + } + + // ------------------------------------------------ + // writing the files + // ------------------------------------------------ + WriteShp(shpfile, cBack); + WriteShx(shxfile, cBack); + + fclose(shpfile); + fclose(shxfile); + + // ------------------------------------------------ + // saving dbf table + // ------------------------------------------------ + const CComBSTR bstrDbf(newDbfName); + _table->SaveAs(bstrDbf, cBack, retval); + + if (*retval != VARIANT_TRUE) + { + _table->get_LastErrorCode(&_lastErrorCode); + _wunlink(newShpName); + _wunlink(newShxName); + return S_OK; + } + + // ------------------------------------------------- + // switching to the new files + // ------------------------------------------------- + shpfile = _wfopen(newShpName, L"rb"); + shxfile = _wfopen(newShxName, L"rb"); + + if (_shpfile != nullptr) fclose(_shpfile); + _shpfile = shpfile; + + if (_shxfile != nullptr) fclose(_shxfile); + _shxfile = shxfile; + + // update all filenames: + _shpfileName = newShpName; // saving of shp filename should be done before writing the projection; + _shxfileName = newShxName; // otherwise projection string will be written to the memory + _dbffileName = newDbfName; + _prjfileName = newShpName.Left(newShpName.GetLength() - 3) + L"prj"; + + _sourceType = sstDiskBased; + + // saving projection in new format + VARIANT_BOOL vbretval, isEmpty; + _geoProjection->get_IsEmpty(&isEmpty); + if (!isEmpty) + { + const CComBSTR bstr(_prjfileName); + _geoProjection->WriteToFileEx(bstr, VARIANT_TRUE, &vbretval); + } + + if (_useQTree) + GenerateQTree(); + + *retval = VARIANT_TRUE; + } + + // restoring callback + if (callbackIsNull) + { + _globalCallback = nullptr; + } + + return S_OK; +} + +// ************************************************************** +// Save() +// ************************************************************** +// saving without exiting edit mode +STDMETHODIMP CShapefile::Save(ICallback* cBack, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retval = VARIANT_FALSE; + + if (_globalCallback == nullptr && cBack != nullptr) + { + _globalCallback = cBack; + _globalCallback->AddRef(); + } + + // no edits were made; it doesn't make sense to save it + if (_isEditingShapes == FALSE) + { + ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); + return S_OK; + } + + if (VerifyMemShapes(_globalCallback) == FALSE) + { + // error Code is set in function + return S_OK; + } + + if (!this->ValidateOutput(this, "Save", "Shapefile", false)) + return S_OK; + + // compute the extents + VARIANT_BOOL res; + RefreshExtents(&res); + + // ------------------------------------------------- + // Reopen the files in the write mode + // ------------------------------------------------- + if (_shpfile && _shxfile) + { + _shpfile = _wfreopen(_shpfileName, L"wb+", _shpfile); + _shxfile = _wfreopen(_shxfileName, L"wb+", _shxfile); + } + else + { + _shpfile = _wfopen(_shpfileName, L"wb+"); + _shxfile = _wfopen(_shxfileName, L"wb+"); + } + + if (_shpfile == nullptr || _shxfile == nullptr) + { + if (_shxfile != nullptr) + { + fclose(_shxfile); + _shxfile = nullptr; + _lastErrorCode = tkCANT_OPEN_SHX; + } + if (_shpfile != nullptr) + { + fclose(_shpfile); + _shpfile = nullptr; + _lastErrorCode = tkCANT_OPEN_SHP; + } + *retval = FALSE; + + ErrorMessage(_lastErrorCode); + } + else + { + _writing = true; + + // ------------------------------------------------- + // Writing the files + // ------------------------------------------------- + WriteShp(_shpfile, cBack); + WriteShx(_shxfile, cBack); + + if (_useQTree) + GenerateQTree(); + + // ------------------------------------------------- + // Reopen the updated files + // ------------------------------------------------- + _shpfile = _wfreopen(_shpfileName, L"rb+", _shpfile); + _shxfile = _wfreopen(_shxfileName, L"rb+", _shxfile); + + if (_shpfile == nullptr || _shxfile == nullptr) + { + if (_shxfile != nullptr) + { + fclose(_shxfile); + _shxfile = nullptr; + _lastErrorCode = tkCANT_OPEN_SHX; + } + if (_shpfile != nullptr) + { + fclose(_shpfile); + _shpfile = nullptr; + _lastErrorCode = tkCANT_OPEN_SHP; + } + *retval = FALSE; + + ErrorMessage(_lastErrorCode); + } + else + { + //Save the table file + _table->Save(cBack, retval); + + _sourceType = sstDiskBased; + + // saving projection in new format + VARIANT_BOOL vbretval, isEmpty; + _geoProjection->get_IsEmpty(&isEmpty); + if (!isEmpty) + { + const CComBSTR bstr(_prjfileName); + _geoProjection->WriteToFileEx(bstr, VARIANT_TRUE, &vbretval); + } + + *retval = VARIANT_TRUE; + } + } + + _writing = false; + return S_OK; +} + +// ************************************************************ +// Resource() +// ************************************************************ +STDMETHODIMP CShapefile::Resource(BSTR newShpPath, VARIANT_BOOL* retval) +{ + USES_CONVERSION; + Close(retval); + Open(newShpPath, nullptr, retval); + return S_OK; +} +#pragma endregion + +// *********************************************************************** +// Clone() +// *********************************************************************** +// Creates new shapefile with the same type and fields as existing one +STDMETHODIMP CShapefile::Clone(IShapefile** retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + ShapefileHelper::CloneCore(this, retVal, _shpfiletype); + return S_OK; +} + +// ************************************************************ +// get_Extents() +// ************************************************************ +STDMETHODIMP CShapefile::get_Extents(IExtents** pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + IExtents* bBox = nullptr; + ComHelper::CreateExtents(&bBox); + + // Extents could change because of the moving of points of a single shape + // It's difficult to track such changes, so we still need to recalculate them + // here to enforce proper drawing; _fastMode mode - for those who want + // to call refresh extents theirselfs + if (!_fastMode) + { + VARIANT_BOOL vbretval; + this->RefreshExtents(&vbretval); + } + + bBox->SetBounds(_minX, _minY, _minZ, _maxX, _maxY, _maxZ); + bBox->SetMeasureBounds(_minM, _maxM); + *pVal = bBox; + + return S_OK; +} + +#pragma region AttributeTable +// **************************************************************** +// EditInsertField() +// **************************************************************** +STDMETHODIMP CShapefile::EditInsertField(IField* NewField, long* FieldIndex, ICallback* cBack, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + if (cBack == nullptr && _globalCallback != nullptr) + cBack = _globalCallback; + + if (_table != nullptr) + { + _table->EditInsertField(NewField, FieldIndex, cBack, retval); + } + else + { + *retval = VARIANT_FALSE; + _lastErrorCode = tkFILE_NOT_OPEN; + ErrorMessage(_lastErrorCode, cBack); + return S_OK; + } + + if (*retval == VARIANT_FALSE) + { + _table->get_LastErrorCode(&_lastErrorCode); + *retval = VARIANT_FALSE; + } + + return S_OK; +} + +// **************************************************************** +// EditDeleteField() +// **************************************************************** +STDMETHODIMP CShapefile::EditDeleteField(long FieldIndex, ICallback* cBack, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + if (_globalCallback == nullptr && cBack != nullptr) + { + _globalCallback = cBack; + _globalCallback->AddRef(); + } + + if (_table != nullptr) + { + _table->EditDeleteField(FieldIndex, cBack, retval); + } + else + { + *retval = VARIANT_FALSE; + ErrorMessage(tkFILE_NOT_OPEN); + return S_OK; + } + + if (*retval == VARIANT_FALSE) + { + _table->get_LastErrorCode(&_lastErrorCode); + *retval = VARIANT_FALSE; + } + + return S_OK; +} + +// **************************************************************** +// EditCellValue() +// **************************************************************** +STDMETHODIMP CShapefile::EditCellValue(long FieldIndex, long ShapeIndex, VARIANT NewVal, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + if (_table != nullptr) + { + _table->EditCellValue(FieldIndex, ShapeIndex, NewVal, retval); + } + else + { + *retval = VARIANT_FALSE; + ErrorMessage(tkFILE_NOT_OPEN); + return S_OK; + } + + if (*retval == VARIANT_FALSE) + { + _table->get_LastErrorCode(&_lastErrorCode); + } + + return S_OK; +} + +// **************************************************************** +// StartEditingTable() +// **************************************************************** +STDMETHODIMP CShapefile::StartEditingTable(ICallback* cBack, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + if (_appendMode) + { + ErrorMessage(tkDBF_NO_EDIT_MODE_WHEN_APPENDING); + *retval = VARIANT_FALSE; + return S_OK; + } + + if (_globalCallback == nullptr && cBack != nullptr) + { + _globalCallback = cBack; + _globalCallback->AddRef(); + } + + if (_table != nullptr) + { + _table->StartEditingTable(cBack, retval); + } + else + { + *retval = VARIANT_FALSE; + ErrorMessage(tkFILE_NOT_OPEN); + return S_OK; + } + + if (*retval == VARIANT_FALSE) + { + _table->get_LastErrorCode(&_lastErrorCode); + *retval = VARIANT_FALSE; + } + + return S_OK; +} + +// **************************************************************** +// StopEditingTable() +// **************************************************************** +STDMETHODIMP CShapefile::StopEditingTable(VARIANT_BOOL ApplyChanges, ICallback* cBack, VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + if (_globalCallback == nullptr && cBack != nullptr) + { + _globalCallback = cBack; + _globalCallback->AddRef(); + } + + if (_table != nullptr) + { + _table->StopEditingTable(ApplyChanges, cBack, retval); + } + else + { + *retval = VARIANT_FALSE; + ErrorMessage(tkFILE_NOT_OPEN); + return S_OK; + } + + if (*retval == FALSE) + { + _table->get_LastErrorCode(&_lastErrorCode); + *retval = VARIANT_FALSE; + } + + return S_OK; +} + +// ***************************************************************** +// get_Field() +// ***************************************************************** +STDMETHODIMP CShapefile::get_Field(long FieldIndex, IField** pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + if (_table != nullptr) + { + _table->get_Field(FieldIndex, pVal); + if (*pVal != nullptr) + { + // we need to report error from field class, and will use callback from this class for it + ICallback* cBack = nullptr; + if ((*pVal)->get_GlobalCallback(&cBack) == NULL && this->_globalCallback != nullptr) + (*pVal)->put_GlobalCallback(_globalCallback); + + if (cBack != nullptr) + cBack->Release(); // we put a reference in field class so must release it here + } + } + else + { + ErrorMessage(tkFILE_NOT_OPEN); + return S_OK; + } + + return S_OK; +} + +// ***************************************************************** +// get_FieldByName() +// ***************************************************************** +STDMETHODIMP CShapefile::get_FieldByName(BSTR Fieldname, IField** pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + USES_CONVERSION; + + long max; + + CString strFieldname; + IField* testVal; + + _table->get_NumFields(&max); + if (_table != nullptr) + { + if (_tcslen(OLE2CA(Fieldname)) > 0) + { + strFieldname = OLE2A(Fieldname); + } + else + { + ErrorMessage(tkZERO_LENGTH_STRING); + } + + for (int fld = 0; fld < max; fld++) + { + _table->get_Field(fld, &testVal); + CComBSTR Testname; + testVal->get_Name(&Testname); + CString strTestname = OLE2A(Testname); + if (strTestname.CompareNoCase(strFieldname) == 0) + { + *pVal = testVal; + return S_OK; + } + testVal->Release(); + } + } + else + { + ErrorMessage(tkFILE_NOT_OPEN); + return S_OK; + } + + // we did not have a file error, but we also didn't match the name + pVal = nullptr; + return S_OK; +} + +// ***************************************************************** +// get_CellValue() +// ***************************************************************** +STDMETHODIMP CShapefile::get_CellValue(long FieldIndex, long ShapeIndex, VARIANT* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + if (_table != nullptr) + { + _table->get_CellValue(FieldIndex, ShapeIndex, pVal); + } + else + { + ErrorMessage(tkFILE_NOT_OPEN); + return S_OK; + } + + return S_OK; +} + +// ***************************************************************** +// get_EditingTable() +// ***************************************************************** +STDMETHODIMP CShapefile::get_EditingTable(VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + if (_table != nullptr) + { + _table->get_EditingTable(pVal); + } + else + { + *pVal = VARIANT_FALSE; + ErrorMessage(tkFILE_NOT_OPEN); + return S_OK; + } + + return S_OK; +} + +// ************************************************************* +// get_Table() +// ************************************************************* +STDMETHODIMP CShapefile::get_Table(ITable** retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retVal = _table; + if (_table) + { + _table->AddRef(); + } + return S_OK; +} +#pragma endregion + +#pragma region DrawingOptions + +// ************************************************************* +// get_ShapeRotation() +// ************************************************************* +STDMETHODIMP CShapefile::get_ShapeRotation(long ShapeIndex, double* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) + { + *pVal = -1; + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + *pVal = _shapeData[ShapeIndex]->rotation; + return S_OK; +} + +STDMETHODIMP CShapefile::put_ShapeRotation(long ShapeIndex, double newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + _shapeData[ShapeIndex]->rotation = static_cast(newVal); + + return S_OK; +} + +// ************************************************************* +// get_ShapeVisible() +// ************************************************************* +STDMETHODIMP CShapefile::get_ShapeVisible(long ShapeIndex, VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *pVal = VARIANT_FALSE; + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + // this particular shape was not hidden explicitly or via visibility expression + if (!_shapeData[ShapeIndex]->hidden() && _shapeData[ShapeIndex]->isVisible()) + { + long ctIndex = -1; + get_ShapeCategory(ShapeIndex, &ctIndex); + if (ctIndex == -1) + { + // no category, check default options + _defaultDrawOpt->get_Visible(pVal); + } + else + { + // there is category, check whether it is visible + CComPtr ct = nullptr; + get_ShapeCategory3(ShapeIndex, &ct); + if (ct) + { + CComPtr options = nullptr; + ct->get_DrawingOptions(&options); + if (options) + { + options->get_Visible(pVal); + } + } + } + } + } + return S_OK; +} + +// ************************************************************* +// ShapeIsHidden() +// ************************************************************* +STDMETHODIMP CShapefile::get_ShapeIsHidden(LONG shapeIndex, VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (shapeIndex < 0 || shapeIndex >= (long)_shapeData.size()) + { + *pVal = VARIANT_FALSE; + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + *pVal = _shapeData[shapeIndex]->hidden() ? VARIANT_TRUE : VARIANT_FALSE; + } + return S_OK; +} + +STDMETHODIMP CShapefile::put_ShapeIsHidden(LONG shapeIndex, VARIANT_BOOL newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (shapeIndex < 0 || shapeIndex >= (long)_shapeData.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + _shapeData[shapeIndex]->hidden(newVal != 0); + + return S_OK; +} + +// ************************************************************* +// get_ShapeModified() +// ************************************************************* +STDMETHODIMP CShapefile::get_ShapeModified(long ShapeIndex, VARIANT_BOOL* retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) + { + *retVal = -1; + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + *retVal = _shapeData[ShapeIndex]->modified() ? VARIANT_TRUE : VARIANT_FALSE; + } + + return S_OK; +} + +STDMETHODIMP CShapefile::put_ShapeModified(long ShapeIndex, VARIANT_BOOL newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + _shapeData[ShapeIndex]->modified(newVal != 0); + } + + return S_OK; +} + + +// ************************************************************* +// get_ShapeCategory() +// ************************************************************* +STDMETHODIMP CShapefile::get_ShapeCategory(long ShapeIndex, long* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) //_numShapes) + { + *pVal = -1; + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + *pVal = _shapeData[ShapeIndex]->category; + return S_OK; +} + +STDMETHODIMP CShapefile::put_ShapeCategory(long ShapeIndex, long newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) //_numShapes ) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + _shapeData[ShapeIndex]->category = (int)newVal; + + return S_OK; +} + +// ************************************************************* +// get_ShapeCategory2() +// ************************************************************* +STDMETHODIMP CShapefile::put_ShapeCategory2(long ShapeIndex, BSTR categoryName) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + int index; + _categories->get_CategoryIndexByName(categoryName, &index); + if (index == -1) + { + ErrorMessage(tkCATEGORY_WASNT_FOUND); + } + else + { + _shapeData[ShapeIndex]->category = (int)index; + } + } + return S_OK; +} + +STDMETHODIMP CShapefile::get_ShapeCategory2(long ShapeIndex, BSTR* categoryName) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + const int index = _shapeData[ShapeIndex]->category; + long count; + _categories->get_Count(&count); + if (index >= 0 && index < count) + { + IShapefileCategory* ct; + _categories->get_Item(index, &ct); + ct->get_Name(categoryName); + ct->Release(); + return S_OK; + } + ErrorMessage(tkCATEGORY_WASNT_FOUND); + } + *categoryName = SysAllocString(L""); + return S_OK; +} + +// ************************************************************* +// put_ShapeCategory3() +// ************************************************************* +STDMETHODIMP CShapefile::put_ShapeCategory3(long ShapeIndex, IShapefileCategory* category) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + int index; + _categories->get_CategoryIndex(category, &index); + if (index == -1) + { + ErrorMessage(tkCATEGORY_WASNT_FOUND); + } + else + { + _shapeData[ShapeIndex]->category = (int)index; + } + } + return S_OK; +} + +STDMETHODIMP CShapefile::get_ShapeCategory3(long ShapeIndex, IShapefileCategory** category) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *category = nullptr; + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + const int index = _shapeData[ShapeIndex]->category; + long count; + _categories->get_Count(&count); + if (index >= 0 && index < count) + { + IShapefileCategory* ct; + _categories->get_Item(index, &ct); + *category = ct; // ref was added in the get_Item + } + else + { + ErrorMessage(tkCATEGORY_WASNT_FOUND); + } + } + return S_OK; +} + +// ******************************************************************* +// SelectionDrawingOptions() +// ******************************************************************* +// Returns and sets parameters used to draw selection for the shapefile. +STDMETHODIMP CShapefile::get_SelectionDrawingOptions(IShapeDrawingOptions** pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *pVal = _selectDrawOpt; + if (_selectDrawOpt) + _selectDrawOpt->AddRef(); + return S_OK; +} + +STDMETHODIMP CShapefile::put_SelectionDrawingOptions(IShapeDrawingOptions* newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (!newVal) + { + ErrorMessage(tkINVALID_PARAMETER_VALUE); + } + else + { + ComHelper::SetRef(newVal, (IDispatch**)&_selectDrawOpt, false); + } + return S_OK; +} + +// ******************************************************************* +// DeafultDrawingOptions() +// ******************************************************************* +// Returns and sets parameters used to draw shapefile by default. +STDMETHODIMP CShapefile::get_DefaultDrawingOptions(IShapeDrawingOptions** pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *pVal = _defaultDrawOpt; + if (_defaultDrawOpt) + _defaultDrawOpt->AddRef(); + return S_OK; +} + +STDMETHODIMP CShapefile::put_DefaultDrawingOptions(IShapeDrawingOptions* newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + if (!newVal) + { + ErrorMessage(tkINVALID_PARAMETER_VALUE); + } + else + { + ComHelper::SetRef(newVal, (IDispatch**)&_defaultDrawOpt); + } + return S_OK; +} + +// *********************************************************************** +// put_ReferenceToCategories +// *********************************************************************** +void CShapefile::put_ReferenceToCategories(bool bNullReference) +{ + if (_categories == nullptr) return; + auto* coCategories = dynamic_cast(_categories); + if (!bNullReference) + coCategories->put_ParentShapefile(this); + else + coCategories->put_ParentShapefile(nullptr); +}; + +// *********************************************************************** +// get/put_Categories +// *********************************************************************** +STDMETHODIMP CShapefile::get_Categories(IShapefileCategories** pVal) +{ + *pVal = _categories; + if (_categories != nullptr) + _categories->AddRef(); + return S_OK; +} + +STDMETHODIMP CShapefile::put_Categories(IShapefileCategories* newVal) +{ + if (ComHelper::SetRef((IDispatch*)newVal, (IDispatch**)&_categories, false)) + { + ((CShapefileCategories*)_categories)->put_ParentShapefile(this); + } + return S_OK; +} +#pragma endregion + +// ******************************************************************** +// get_SelectionColor +// ******************************************************************** +STDMETHODIMP CShapefile::get_SelectionColor(OLE_COLOR* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *retval = _selectionColor; + return S_OK; +} + +STDMETHODIMP CShapefile::put_SelectionColor(OLE_COLOR newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + _selectionColor = newVal; + return S_OK; +} + +// ******************************************************************** +// get_SelectionTransparency +// ******************************************************************** +STDMETHODIMP CShapefile::get_SelectionTransparency(BYTE* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *retval = _selectionTransparency; + return S_OK; +} + +STDMETHODIMP CShapefile::put_SelectionTransparency(BYTE newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (newVal > 255) newVal = 255; + _selectionTransparency = newVal; + return S_OK; +} + +// ******************************************************************** +// get_SelectionAppearance +// ******************************************************************** +STDMETHODIMP CShapefile::get_SelectionAppearance(tkSelectionAppearance* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *retval = _selectionAppearance; + return S_OK; +} + +STDMETHODIMP CShapefile::put_SelectionAppearance(tkSelectionAppearance newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + _selectionAppearance = newVal; + return S_OK; +} + +// ******************************************************************** +// get_PointCollisionMode +// ******************************************************************** +STDMETHODIMP CShapefile::get_CollisionMode(tkCollisionMode* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *retval = _collisionMode; + return S_OK; +} + +STDMETHODIMP CShapefile::put_CollisionMode(tkCollisionMode newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + _collisionMode = newVal; + return S_OK; +} + +#pragma region "Seialization" +// ******************************************************** +// Serialize() +// ******************************************************** +STDMETHODIMP CShapefile::Serialize(VARIANT_BOOL SaveSelection, BSTR* retVal) +{ + return Serialize2(SaveSelection, VARIANT_FALSE, retVal); +} + +STDMETHODIMP CShapefile::Serialize2(VARIANT_BOOL SaveSelection, VARIANT_BOOL SerializeCategories, BSTR* retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + CPLXMLNode* psTree = this->SerializeCore(VARIANT_TRUE, "ShapefileClass", SerializeCategories != 0); + Utility::SerializeAndDestroyXmlTree(psTree, retVal); + return S_OK; +} + +// ******************************************************** +// SerializeCore() +// ******************************************************** +CPLXMLNode* CShapefile::SerializeCore(VARIANT_BOOL SaveSelection, CString ElementName, bool serializeCategories) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + USES_CONVERSION; + + CPLXMLNode* psTree = CPLCreateXMLNode(nullptr, CXT_Element, ElementName); + + if (psTree) + { + CString s = OLE2CA(_expression); + if (s != "") + Utility::CPLCreateXMLAttributeAndValue(psTree, "VisibilityExpression", s); + + + if (_useQTree != FALSE) + Utility::CPLCreateXMLAttributeAndValue(psTree, "UseQTree", CPLString().Printf("%d", (int)_useQTree)); + + if (_collisionMode != LocalList) + Utility::CPLCreateXMLAttributeAndValue(psTree, "CollisionMode", + CPLString().Printf("%d", (int)_collisionMode)); + + if (_selectionAppearance != saSelectionColor) + Utility::CPLCreateXMLAttributeAndValue(psTree, "SelectionAppearance", + CPLString().Printf("%d", (int)_selectionAppearance)); + + if (_selectionColor != RGB(255, 255, 0)) + Utility::CPLCreateXMLAttributeAndValue(psTree, "SelectionColor", + CPLString().Printf("%d", (int)_selectionColor)); + + if (_selectionTransparency != 180) + Utility::CPLCreateXMLAttributeAndValue(psTree, "SelectionTransparency", + CPLString().Printf("%d", (int)_selectionTransparency)); + + if (_minDrawingSize != 1) + Utility::CPLCreateXMLAttributeAndValue(psTree, "MinDrawingSize", CPLString().Printf("%d", _minDrawingSize)); + + // for in-memory shapefiles only + if (_sourceType == sstInMemory) + Utility::CPLCreateXMLAttributeAndValue(psTree, "ShpType", + CPLString().Printf("%d", (int)this->_shpfiletype)); + + s = OLE2CA(_sortField); + if (s != "") + Utility::CPLCreateXMLAttributeAndValue(psTree, "SortField", s); + + if (_sortAscending != VARIANT_FALSE) + Utility::CPLCreateXMLAttributeAndValue(psTree, "SortAscending", + CPLString().Printf("%d", (int)_sortAscending)); + + // drawing options + CPLXMLNode* node = ((CShapeDrawingOptions*)_defaultDrawOpt)->SerializeCore("DefaultDrawingOptions"); + if (node) + { + CPLAddXMLChild(psTree, node); + } + + if (_selectionAppearance == saDrawingOptions) + { + node = ((CShapeDrawingOptions*)_selectDrawOpt)->SerializeCore("SelectionDrawingOptions"); + if (node) + { + CPLAddXMLChild(psTree, node); + } + } + + // categories + node = ((CShapefileCategories*)_categories)->SerializeCore("ShapefileCategoriesClass"); + if (node) + { + CPLAddXMLChild(psTree, node); + } + + // labels + CPLXMLNode* psLabels = ((CLabels*)_labels)->SerializeCore("LabelsClass"); + if (psLabels) + { + CPLAddXMLChild(psTree, psLabels); + } + + // charts + CPLXMLNode* psCharts = ((CCharts*)_charts)->SerializeCore("ChartsClass"); + if (psCharts) + { + CPLAddXMLChild(psTree, psCharts); + } + + // ---------------------------------------------------- + // selection + // ---------------------------------------------------- + long numSelected; + this->get_NumSelected(&numSelected); + + if (numSelected > 0 && SaveSelection) + { + auto* selection = new char[_shapeData.size() + 1]; + selection[_shapeData.size()] = '\0'; + for (unsigned int i = 0; i < _shapeData.size(); i++) + { + selection[i] = _shapeData[i]->selected() ? '1' : '0'; + } + + CPLXMLNode* nodeSelection = CPLCreateXMLElementAndValue(psTree, "Selection", selection); + if (nodeSelection) + { + Utility::CPLCreateXMLAttributeAndValue(nodeSelection, "TotalCount", + CPLString().Printf("%d", _shapeData.size())); + Utility::CPLCreateXMLAttributeAndValue(nodeSelection, "SelectedCount", + CPLString().Printf("%d", numSelected)); + } + delete[] selection; + } + + // ---------------------------------------------------- + // serialization of category indices + // ---------------------------------------------------- + // Paul Meems TODO: This variable comes in as a parameter as well. + // Is this correct? + bool serializeCategories = false; + + for (auto& i : _shapeData) + { + if (i->category != -1) + { + serializeCategories = true; + } + } + + if (serializeCategories) + { + s = ""; + // doing it with CString is ugly of course, better to allocate a buffer + CString temp; + for (auto& i : _shapeData) + { + temp.Format("%d,", i->category); + s += temp; + } + + // when there are no indices assigned, write an empty node with Count = 0; + // to signal, that categories must not be applied automatically (behavior for older versions) + CPLXMLNode* nodeCats = CPLCreateXMLElementAndValue(psTree, "CategoryIndices", s.GetBuffer()); + if (nodeCats) + { + Utility::CPLCreateXMLAttributeAndValue(nodeCats, "Count", + CPLString().Printf( + "%d", serializeCategories ? _shapeData.size() : 0)); + } + } + + // ---------------------------------------------------- + // table + // ---------------------------------------------------- + if (_table) + { + CPLXMLNode* psTable = ((CTableClass*)_table)->SerializeCore("TableClass"); + if (psTable) + { + CPLAddXMLChild(psTree, psTable); + } + } + } + return psTree; +} + +// ******************************************************** +// Deserialize() +// ******************************************************** +STDMETHODIMP CShapefile::Deserialize(VARIANT_BOOL LoadSelection, BSTR newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + USES_CONVERSION; + + CString s = OLE2CA(newVal); + CPLXMLNode* node = CPLParseXMLString(s.GetString()); + if (node) + { + CPLXMLNode* nodeSf = CPLGetXMLNode(node, "=ShapefileClass"); + if (nodeSf) + { + this->DeserializeCore(VARIANT_TRUE, nodeSf); + } + CPLDestroyXMLNode(node); + } + return S_OK; +} + +// ******************************************************** +// DeserializeCore() +// ******************************************************** +bool CShapefile::DeserializeCore(VARIANT_BOOL LoadSelection, CPLXMLNode* node) +{ + USES_CONVERSION; + + if (!node) + return false; + + CString s = CPLGetXMLValue(node, "VisibilityExpression", nullptr); + SysFreeString(_expression); + _expression = A2BSTR(s); + + s = CPLGetXMLValue(node, "UseQTree", nullptr); + _useQTree = s != "" ? (BOOL)atoi(s.GetString()) : FALSE; + + s = CPLGetXMLValue(node, "CollisionMode", nullptr); + _collisionMode = s != "" ? (tkCollisionMode)atoi(s.GetString()) : LocalList; + + s = CPLGetXMLValue(node, "SelectionAppearance", nullptr); + _selectionAppearance = s != "" ? (tkSelectionAppearance)atoi(s.GetString()) : saSelectionColor; + + s = CPLGetXMLValue(node, "SelectionColor", nullptr); + _selectionColor = s != "" ? (OLE_COLOR)atoi(s.GetString()) : RGB(255, 255, 0); + + s = CPLGetXMLValue(node, "SelectionTransparency", nullptr); + _selectionTransparency = s != "" ? (unsigned char)atoi(s.GetString()) : 180; + + s = CPLGetXMLValue(node, "MinDrawingSize", nullptr); + _minDrawingSize = s != "" ? atoi(s.GetString()) : 1; + + s = CPLGetXMLValue(node, "SortField", nullptr); + const CComBSTR bstrSortField = A2W(s); + this->put_SortField(bstrSortField); + + s = CPLGetXMLValue(node, "SortAscending", nullptr); + const VARIANT_BOOL sortAsc = s != "" ? (VARIANT_BOOL)atoi(s.GetString()) : VARIANT_FALSE; + this->put_SortAscending(sortAsc); + + if (_sourceType == sstInMemory) + { + s = CPLGetXMLValue(node, "ShpType", nullptr); + if (s != "") + { + _shpfiletype = (ShpfileType)atoi(s.GetString()); + } + } + + // drawing options + CPLXMLNode* psChild = CPLGetXMLNode(node, "DefaultDrawingOptions"); + if (psChild) + { + ((CShapeDrawingOptions*)_defaultDrawOpt)->DeserializeCore(psChild); + } + + if (_selectionAppearance == saDrawingOptions) + { + psChild = CPLGetXMLNode(node, "SelectionDrawingOptions"); + if (psChild) + { + ((CShapeDrawingOptions*)_selectDrawOpt)->DeserializeCore(psChild); + } + } + + // Categories + psChild = CPLGetXMLNode(node, "ShapefileCategoriesClass"); + if (psChild) + { + ((CShapefileCategories*)_categories)->DeserializeCore(psChild, false); + } + + CPLXMLNode* nodeCats = CPLGetXMLNode(node, "CategoryIndices"); + bool needsApplyExpression = true; + if (nodeCats) + { + CString indices = CPLGetXMLValue(nodeCats, "=CategoryIndices", ""); + if (indices.GetLength() > 0) + { + s = CPLGetXMLValue(nodeCats, "Count", "0"); + const long savedCount = atoi(s); + int foundCount = 0; + char* buffer = indices.GetBuffer(); + for (int i = 0; i < indices.GetLength(); i++) + { + if (buffer[i] == ',') + { + foundCount++; + } + } + + if (foundCount == savedCount && foundCount == _shapeData.size()) + { + const int size = _shapeData.size(); + int pos = 0, count = 0; + CString ct = indices.Tokenize(",", pos); + while (ct.GetLength() != 0 && count < size) + { + _shapeData[count]->category = atoi(ct); + ct = indices.Tokenize(",", pos); + count++; + }; + bool needsApplyExpression = false; + } + } + } + + // If no indices or invalid indices, re-apply: + if (needsApplyExpression) + { + ((CShapefileCategories*)_categories)->ApplyExpressions(); + } + + // Labels + psChild = CPLGetXMLNode(node, "LabelsClass"); + if (psChild) + { + ((CLabels*)_labels)->DeserializeCore(psChild); + } + + // Charts + psChild = CPLGetXMLNode(node, "ChartsClass"); + if (psChild) + { + ((CCharts*)_charts)->DeserializeCore(psChild); + } + + // selection + CPLXMLNode* nodeSelection = CPLGetXMLNode(node, "Selection"); + if (nodeSelection && LoadSelection) + { + this->SelectNone(); + + s = CPLGetXMLValue(nodeSelection, "TotalCount", "0"); + const long count = atoi(s); + s = CPLGetXMLValue(nodeSelection, "=Selection", ""); + if (s.GetLength() == count && s.GetLength() == _shapeData.size()) + { + char* selection = s.GetBuffer(); + for (unsigned int i = 0; i < _shapeData.size(); i++) + { + if (selection[i] == '1') + { + _shapeData[i]->selected(true); + } + } + } + } + + + // table + if (_table) + { + psChild = CPLGetXMLNode(node, "TableClass"); + if (psChild) + { + ((CTableClass*)_table)->DeserializeCore(psChild); + } + } + return true; +} +#pragma endregion + + +#pragma region Projection +// ***************************************************************** +// get_Projection() +// ***************************************************************** +STDMETHODIMP CShapefile::get_Projection(BSTR* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + _geoProjection->ExportToProj4(pVal); + return S_OK; +} + +// ***************************************************************** +// put_Projection() +// ***************************************************************** +STDMETHODIMP CShapefile::put_Projection(BSTR proj4Projection) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + USES_CONVERSION; + + VARIANT_BOOL vbretval; + _geoProjection->ImportFromProj4(proj4Projection, &vbretval); + if (vbretval) + { + const CComBSTR bstrFilename(_prjfileName); + _geoProjection->WriteToFileEx(bstrFilename, VARIANT_TRUE, &vbretval); + } + return S_OK; +} + +// ***************************************************************** +// get_GeoProjection() +// ***************************************************************** +STDMETHODIMP CShapefile::get_GeoProjection(IGeoProjection** retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (_geoProjection) + _geoProjection->AddRef(); + + *retVal = _geoProjection; + return S_OK; +} + +// ***************************************************************** +// put_GeoProjection() +// ***************************************************************** +STDMETHODIMP CShapefile::put_GeoProjection(IGeoProjection* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + ComHelper::SetRef((IDispatch*)pVal, (IDispatch**)&_geoProjection, false); + if (_prjfileName.GetLength() != 0) + { + VARIANT_BOOL vbretval; + const CComBSTR bstr(_prjfileName); + _geoProjection->WriteToFileEx(bstr, VARIANT_TRUE, &vbretval); + } + return S_OK; +} + +// **************************************************************** +// get_IsGeographicProjection +// **************************************************************** +STDMETHODIMP CShapefile::get_IsGeographicProjection(VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + *pVal = VARIANT_FALSE; + + if (_geoProjection) + _geoProjection->get_IsGeographic(pVal); + + return S_OK; +} + +// ***************************************************************** +// Reproject() +// ***************************************************************** +STDMETHODIMP CShapefile::Reproject(IGeoProjection* newProjection, LONG* reprojectedCount, IShapefile** retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + if (!this->ReprojectCore(newProjection, reprojectedCount, retVal, false)) + *retVal = nullptr; + return S_OK; +} + +// ***************************************************************** +// ReprojectInPlace() +// ***************************************************************** +STDMETHODIMP CShapefile::ReprojectInPlace(IGeoProjection* newProjection, LONG* reprojectedCount, VARIANT_BOOL* retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (!_isEditingShapes) + { + ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); + *retVal = VARIANT_FALSE; + } + else + { + if (this->ReprojectCore(newProjection, reprojectedCount, nullptr, true)) + { + // spatial index must be deleted, as it became useful all the same + VARIANT_BOOL vb; + RemoveSpatialIndex(&vb); + + // update qtree + if (_useQTree) + GenerateQTree(); + + VARIANT_BOOL vbretval; + this->RefreshExtents(&vbretval); + *retVal = VARIANT_TRUE; + return S_OK; + } + *retVal = NULL; + } + return S_OK; +} + +// ***************************************************************** +// ReprojectCore() +// ***************************************************************** +bool CShapefile::ReprojectCore(IGeoProjection* newProjection, LONG* reprojectedCount, IShapefile** retVal, + bool reprojectInPlace) +{ + // ------------------------------------------------------ + // Validation + // ------------------------------------------------------ + if (!newProjection) + { + ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); + return false; + } + + VARIANT_BOOL isEmpty1, isEmpty2; + newProjection->get_IsEmpty(&isEmpty1); + _geoProjection->get_IsEmpty(&isEmpty2); + if (isEmpty1 || isEmpty2) + { + ErrorMessage(tkPROJECTION_NOT_INITIALIZED); + return false; + } + + if (!ValidateInput(this, "Reproject/ReprojectInPlace", "this", VARIANT_FALSE)) + return false; + + m_globalSettings.gdalErrorMessage = ""; + OGRSpatialReference* projSource = ((CGeoProjection*)_geoProjection)->get_SpatialReference(); + OGRSpatialReference* projTarget = ((CGeoProjection*)newProjection)->get_SpatialReference(); + + OGRCoordinateTransformation* transf = OGRCreateCoordinateTransformation(projSource, projTarget); + if (!transf) + { + m_globalSettings.gdalErrorMessage = CPLGetLastErrorMsg(); + ErrorMessage(tkFAILED_TO_REPROJECT); + return false; + } + + // ------------------------------------------------------ + // Creating output + // ------------------------------------------------------ + if (!reprojectInPlace) + this->Clone(retVal); + + // ------------------------------------------------------ + // Processing + // ------------------------------------------------------ + CComVariant var; + const long numShapes = _shapeData.size(); + long newIndex = 0; + + long numFields, percent = 0; + this->get_NumFields(&numFields); + + VARIANT_BOOL vb = VARIANT_FALSE; + *reprojectedCount = 0; + + for (long i = 0; i < numShapes; i++) + { + CallbackHelper::Progress(_globalCallback, i, numShapes, "Reprojecting...", _key, percent); + + IShape* shp = nullptr; + this->GetValidatedShape(i, &shp); + if (!shp) continue; + + if (!reprojectInPlace) + { + IShape* shpNew = nullptr; + shp->Clone(&shpNew); + shp->Release(); + shp = shpNew; + } + + if (shp) + { + long numPoints; + shp->get_NumPoints(&numPoints); + + if (numPoints > 0) + { + auto* x = new double[numPoints]; + auto* y = new double[numPoints]; + + // extracting coordinates + for (long j = 0; j < numPoints; j++) + { + shp->get_XY(j, x + j, y + j, &vb); + } + + // will work faster after embedding to the CShape class + const BOOL res = transf->Transform(numPoints, x, y); + if (!res) + { + // save error message and continue + if (m_globalSettings.gdalErrorMessage == "") + m_globalSettings.gdalErrorMessage = CPLGetLastErrorMsg(); + } + else + { + // saving updated coordinates + for (long j = 0; j < numPoints; j++) + { + shp->put_XY(j, x[j], y[j], &vb); + } + + if (!reprojectInPlace) + { + // get next available index + (*retVal)->get_NumShapes(&newIndex); + // insert Shape into target at new index + (*retVal)->EditInsertShape(shp, &newIndex, &vb); + + // copy attributes + for (long j = 0; j < numFields; j++) + { + // get cell value at source index i + this->get_CellValue(j, i, &var); + // set cell value into target at new index + (*retVal)->EditCellValue(j, newIndex, var, &vb); + } + } + // + (*reprojectedCount)++; + } + delete[] x; + delete[] y; + } + shp->Release(); + } + } + + if (transf) + { + OGRCoordinateTransformation::DestroyCT(transf); + transf = nullptr; + } + + // function result will be based on successful projection setting + vb = VARIANT_FALSE; + // if at least some rows were reprojected... + if (*reprojectedCount > 0) + { + // setting new projection + if (reprojectInPlace) + { + // vb result will be used to determine overall success + _geoProjection->CopyFrom(newProjection, &vb); + } + else + { + IGeoProjection* proj = nullptr; + (*retVal)->get_GeoProjection(&proj); + if (proj) + { + // vb result will be used to determine overall success + proj->CopyFrom(newProjection, &vb); + proj->Release(); + } + } + } + + // inserted shapes were marked as modified, correct this + if (reprojectInPlace) + ShapefileHelper::ClearShapefileModifiedFlag(this); + else + ShapefileHelper::ClearShapefileModifiedFlag(*retVal); + + // -------------------------------------- + // Output validation + // -------------------------------------- + CallbackHelper::ProgressCompleted(_globalCallback, _key); + + if (!reprojectInPlace) + { + this->ValidateOutput(retVal, "Reproject/ReprojectInPlace", "Shapefile", false); + } + else + { + this->ValidateOutput(this, "Reproject/ReprojectInPlace", "Shapefile", false); + } + + // it's critical to set correct projection, so false will be returned if it wasn't done + return vb != 0; +} +#pragma endregion + +// ***************************************************************** +// FixUpShapes() +// ***************************************************************** +STDMETHODIMP CShapefile::FixUpShapes(IShapefile** retVal, VARIANT_BOOL* fixed) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + // MWGIS-90: default to all shapes: + FixUpShapes2(VARIANT_FALSE, retVal, fixed); + + return S_OK; +} + +// ********************************************************* +// FixUpShapes2() +// ********************************************************* +STDMETHODIMP CShapefile::FixUpShapes2(VARIANT_BOOL SelectedOnly, IShapefile** result, VARIANT_BOOL* fixed) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + *fixed = VARIANT_FALSE; + + if (*result == nullptr) + { + Clone(result); + } + + *fixed = FixupShapesCore(SelectedOnly, *result); + + return S_OK; +} + +// ********************************************************* +// FixupShapesCore() +// ********************************************************* +VARIANT_BOOL CShapefile::FixupShapesCore(VARIANT_BOOL selectedOnly, IShapefile* result) +{ + if (!result) return VARIANT_FALSE; + + tkUnitsOfMeasure units; + _geoProjection->get_LinearUnits(&units); + + long numFields; + this->get_NumFields(&numFields); + + long percent = 0; + const int numShapes = _shapeData.size(); + // VARIANT_BOOL fixed = VARIANT_TRUE; + + for (int i = 0; i < numShapes; i++) + { + CallbackHelper::Progress(_globalCallback, i, numShapes, "Fixing...", _key, percent); + + if (!ShapeAvailable(i, selectedOnly)) + continue; + + IShape* shp = nullptr; + get_Shape(i, &shp); + if (!shp) + { + continue; + } + + IShape* shpNew = nullptr; + shp->FixUp2(units, &shpNew); + shp->Release(); + + // failed to fix the shape? skip it. + if (!shpNew) + { + CString s; + s.Format("Failed to fix shape: %d", i); + CallbackHelper::ErrorMsg("Shapefile", nullptr, "", s); + continue; + } + + long shapeIndex = 0; + result->get_NumShapes(&shapeIndex); + + VARIANT_BOOL vbretval = VARIANT_FALSE; + result->EditInsertShape(shpNew, &shapeIndex, &vbretval); + shpNew->Release(); + + if (vbretval) + { + // TODO: extract, it's definitely used in other methods as well + CComVariant var; + for (int iFld = 0; iFld < numFields; iFld++) + { + get_CellValue(iFld, i, &var); + result->EditCellValue(iFld, shapeIndex, var, &vbretval); + } + } + } + + CallbackHelper::ProgressCompleted(_globalCallback, _key); + + return VARIANT_TRUE; +} + +// ********************************************************* +// GetRelatedShapes() +// ********************************************************* +STDMETHODIMP CShapefile::GetRelatedShapes(long referenceIndex, tkSpatialRelation relation, VARIANT* resultArray, + VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *retval = VARIANT_FALSE; + if (referenceIndex < 0 || referenceIndex > (long)_shapeData.size()) + { + this->ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + return S_OK; + } + + IShape* shp = nullptr; + this->get_Shape(referenceIndex, &shp); + if (shp) + { + this->GetRelatedShapeCore(shp, referenceIndex, relation, resultArray, retval); + shp->Release(); + } + return S_OK; +} + +// ********************************************************* +// GetRelatedShapes2() +// ********************************************************* +STDMETHODIMP CShapefile::GetRelatedShapes2(IShape* referenceShape, tkSpatialRelation relation, VARIANT* resultArray, + VARIANT_BOOL* retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *retval = VARIANT_FALSE; + if (!referenceShape) + { + this->ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); + return S_OK; + } + + this->GetRelatedShapeCore(referenceShape, -1, relation, resultArray, retval); + return S_OK; +} + +// ********************************************************* +// GetRelatedShapeCore() +// ********************************************************* +void CShapefile::GetRelatedShapeCore(IShape* referenceShape, long referenceIndex, tkSpatialRelation relation, + VARIANT* resultArray, VARIANT_BOOL* retval) +{ + if (relation == srDisjoint) + { + // TODO: implement + ErrorMessage(tkMETHOD_NOT_IMPLEMENTED); + return; + } + + // rather than generate geometries for all shapes, + // only generate for those within qtree extent (see below) + //this->ReadGeosGeometries(VARIANT_FALSE); + + // turns on the quad tree + VARIANT_BOOL useQTree = VARIANT_FALSE; + this->get_UseQTree(&useQTree); + if (!useQTree) this->put_UseQTree(VARIANT_TRUE); + + double xMin, xMax, yMin, yMax; + if (((CShape*)referenceShape)->get_ExtentsXY(xMin, yMin, xMax, yMax)) + { + const QTreeExtent query(xMin, xMax, yMax, yMin); + std::vector shapes = this->_qtree->GetNodes(query); + std::vector arr; + + // generate GEOS geometries only for shapes within qtree extent + for (size_t i = 0; i < shapes.size(); i++) + // minimize work by 'select'ing necessary shapes + this->put_ShapeSelected(shapes[i], VARIANT_TRUE); + // now generate only for 'select'ed shapes + this->ReadGeosGeometries(VARIANT_TRUE); + // don't leave shapes 'select'ed + for (size_t i = 0; i < shapes.size(); i++) + this->put_ShapeSelected(shapes[i], VARIANT_FALSE); + + GEOSGeom geomBase; + if (referenceIndex > 0) + { + geomBase = _shapeData[referenceIndex]->geosGeom; + } + else + { + geomBase = GeosConverter::ShapeToGeom(referenceShape); + } + + if (geomBase) + { + for (size_t i = 0; i < shapes.size(); i++) + { + if (i == referenceIndex) + continue; // it doesn't make sense to compare the shape with itself + + // ReSharper disable once CppLocalVariableMayBeConst + GEOSGeom geom = _shapeData[shapes[i]]->geosGeom; + if (geom != nullptr) + { + char res = 0; + switch (relation) + { + case srContains: res = GeosHelper::Contains(geomBase, geom); + break; + case srCrosses: res = GeosHelper::Crosses(geomBase, geom); + break; + case srEquals: res = GeosHelper::Equals(geomBase, geom); + break; + case srIntersects: res = GeosHelper::Intersects(geomBase, geom); + break; + case srOverlaps: res = GeosHelper::Overlaps(geomBase, geom); + break; + case srTouches: res = GeosHelper::Touches(geomBase, geom); + break; + case srWithin: res = GeosHelper::Within(geomBase, geom); + break; + case srDisjoint: break; + default: ; + } + if (res) + { + arr.push_back(shapes[i]); + } + } + } + + if (referenceIndex == -1) + GeosHelper::DestroyGeometry(geomBase); + // the geometry was created in this function so it must be destroyed + } + + *retval = Templates::Vector2SafeArray(&arr, VT_I4, resultArray); + } + + // Don't clear the list here as function may be called in a loop + //this->ClearCachedGeometries(); +} + +// *************************************************** +// get_Identifiable +// *************************************************** +STDMETHODIMP CShapefile::get_Identifiable(VARIANT_BOOL* retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *retVal = _hotTracking; + return S_OK; +} + +STDMETHODIMP CShapefile::put_Identifiable(VARIANT_BOOL newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + _hotTracking = newVal; + return S_OK; +} + +// ***************************************************************** +// EditAddField() +// ***************************************************************** +STDMETHODIMP CShapefile::EditAddField(BSTR name, FieldType type, int precision, int width, long* fieldIndex) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (!this->_table) + { + this->ErrorMessage(tkDBF_FILE_DOES_NOT_EXIST); + } + else + { + _table->EditAddField(name, type, precision, width, fieldIndex); + } + return S_OK; +} + +// ***************************************************************** +// EditAddShape() +// ***************************************************************** +STDMETHODIMP CShapefile::EditAddShape(IShape* shape, long* shapeIndex) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + VARIANT_BOOL retval; + *shapeIndex = _shapeData.size(); + + EditInsertShape(shape, shapeIndex, &retval); + + if (retval == VARIANT_FALSE) + *shapeIndex = -1; + + return S_OK; +} + +// ***************************************************************** +// GetClosestVertex() +// ***************************************************************** +STDMETHODIMP CShapefile::GetClosestVertex(double x, double y, double maxDistance, + long* shapeIndex, long* pointIndex, double* distance, VARIANT_BOOL* retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + *retVal = VARIANT_FALSE; + *shapeIndex = -1; + *pointIndex = -1; + + bool result = false; + if (maxDistance <= 0.0) + { + // search through all shapefile + std::vector ids; + for (size_t i = 0; i < _shapeData.size(); i++) + { + ids.push_back(i); + } + result = ShapefileHelper::GetClosestPoint(this, x, y, maxDistance, ids, shapeIndex, pointIndex, *distance); + } + else + { + std::vector ids; + Extent box(x - maxDistance, x + maxDistance, y - maxDistance, y + maxDistance); + if (this->SelectShapesCore(box, 0.0, SelectMode::INTERSECTION, ids, false)) + { + result = ShapefileHelper::GetClosestPoint(this, x, y, maxDistance, ids, shapeIndex, pointIndex, *distance); + } + } + *retVal = result ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; +} + +// ***************************************************************** +// GetClosestSnapPosition() +// ***************************************************************** +STDMETHODIMP CShapefile::GetClosestSnapPosition(double x, double y, double maxDistance, + long* shapeIndex, double* fx, double* fy, double* distance, VARIANT_BOOL* retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + *retVal = VARIANT_FALSE; + *shapeIndex = -1; + + bool result = false; + if (maxDistance <= 0.0) + { + // search through all shapefile + std::vector ids; + for (size_t i = 0; i < _shapeData.size(); i++) + { + ids.push_back(i); + } + result = ShapefileHelper::GetClosestSnapPosition(this, x, y, maxDistance, ids, shapeIndex, *fx, *fy, *distance); + } + else + { + std::vector ids; + Extent box(x - maxDistance, x + maxDistance, y - maxDistance, y + maxDistance); + if (this->SelectShapesCore(box, 0.0, SelectMode::INTERSECTION, ids, false)) + { + result = ShapefileHelper::GetClosestSnapPosition(this, x, y, maxDistance, ids, shapeIndex, *fx, *fy, *distance); + } + } + *retVal = result ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; +} + +// ***************************************************************** +// HasInvalidShapes() +// ***************************************************************** +STDMETHODIMP CShapefile::HasInvalidShapes(VARIANT_BOOL* result) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *result = VARIANT_FALSE; + const int numShapes = _shapeData.size(); + + for (int i = 0; i < numShapes; i++) + { + IShape* shp = nullptr; + this->get_Shape(i, &shp); + + if (!shp) + { + *result = VARIANT_TRUE; + break; + } + + VARIANT_BOOL retval = VARIANT_TRUE; + shp->get_IsValid(&retval); + shp->Release(); + if (retval == VARIANT_FALSE) + { + *result = VARIANT_TRUE; + break; + } + } + return S_OK; +} + +// ***************************************************************** +// get_UndoList() +// ***************************************************************** +STDMETHODIMP CShapefile::get_UndoList(IUndoList** pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (_undoList) + _undoList->AddRef(); + *pVal = _undoList; + return S_OK; +} + +// ***************************************************************** +// Snappable() +// ***************************************************************** +STDMETHODIMP CShapefile::get_Snappable(VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *pVal = _snappable; + return S_OK; +} + +STDMETHODIMP CShapefile::put_Snappable(VARIANT_BOOL newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + _snappable = newVal; + return S_OK; +} + +// ***************************************************************** +// ShapefileType2D() +// ***************************************************************** +STDMETHODIMP CShapefile::get_ShapefileType2D(ShpfileType* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *pVal = ShapeUtility::Convert2D(_shpfiletype); + return S_OK; +} + +// ***************************************************************** +// FieldIndexByName() +// ***************************************************************** +STDMETHODIMP CShapefile::get_FieldIndexByName(BSTR FieldName, LONG* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + _table->get_FieldIndexByName(FieldName, pVal); + return S_OK; +} + +// *************************************************** +// get_Selectable +// *************************************************** +STDMETHODIMP CShapefile::get_Selectable(VARIANT_BOOL* retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *retVal = _selectable; + return S_OK; +} + +STDMETHODIMP CShapefile::put_Selectable(VARIANT_BOOL newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + _selectable = newVal; + return S_OK; +} + +// ***************************************************************** +// Move() +// ***************************************************************** +STDMETHODIMP CShapefile::Move(DOUBLE xProjOffset, DOUBLE yProjOffset, VARIANT_BOOL* retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *retVal = VARIANT_FALSE; + if (_sourceType != sstInMemory) + { + ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); + return S_OK; + } + long numShapes; + get_NumShapes(&numShapes); + for (long i = 0; i < numShapes; i++) + { + CComPtr shp = nullptr; + get_Shape(i, &shp); + if (shp) + { + shp->Move(xProjOffset, yProjOffset); + } + } + *retVal = VARIANT_TRUE; + return S_OK; +} + +// ***************************************************************** +// get_ShapeRendered() +// ***************************************************************** +STDMETHODIMP CShapefile::get_ShapeRendered(LONG ShapeIndex, VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + *pVal = VARIANT_FALSE; + if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + *pVal = _shapeData[ShapeIndex]->wasRendered() ? VARIANT_TRUE : VARIANT_FALSE; + } + return S_OK; +} + +// ***************************************************************** +// MarkUndrawn() +// ***************************************************************** +void CShapefile::MarkUndrawn() +{ + for (auto& i : _shapeData) + { + i->wasRendered(false); + } +} + +// ************************************************************* +// SortField() +// ************************************************************* +STDMETHODIMP CShapefile::get_SortField(BSTR* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + USES_CONVERSION; + *pVal = OLE2BSTR(_sortField); + + return S_OK; +} + +STDMETHODIMP CShapefile::put_SortField(BSTR newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + SysFreeString(_sortField); + USES_CONVERSION; + _sortField = OLE2BSTR(newVal); + + _sortingChanged = true; + + if (_labels) + { + _labels->UpdateSizeField(); + } + + return S_OK; +} + +// ************************************************************* +// SortAscending() +// ************************************************************* +STDMETHODIMP CShapefile::get_SortAscending(VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + *pVal = _sortAscending; + + return S_OK; +} + +STDMETHODIMP CShapefile::put_SortAscending(VARIANT_BOOL newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + _sortAscending = newVal; + _sortingChanged = true; + + return S_OK; +} + +// ************************************************************* +// UpdateSorting() +// ************************************************************* +STDMETHODIMP CShapefile::UpdateSortField() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + // this will trigger rereading of the table on next redraw + _sortingChanged = true; + + return S_OK; +} + +// ************************************************************* +// GetSorting() +// ************************************************************* +bool CShapefile::GetSorting(vector** indices) +{ + *indices = nullptr; + + if (!_sortingChanged) + { + *indices = &_sorting; + return true; + } + + long fieldIndex; + get_FieldIndexByName(_sortField, &fieldIndex); + + if (fieldIndex == -1) + { + return false; + } + + if (!_table) + { + return false; + } + + _sortingChanged = false; + + if (((CTableClass*)_table)->GetSorting(fieldIndex, _sorting)) + { + if (!_sortAscending) + { + std::reverse(_sorting.begin(), _sorting.end()); + } + + *indices = &_sorting; + return true; + } + CallbackHelper::ErrorMsg("Failed to sort labels"); + + return false; +} diff --git a/src/COM classes/Shapefile.h b/src/COM classes/Shapefile.h index 6cab7240..46f1acb6 100644 --- a/src/COM classes/Shapefile.h +++ b/src/COM classes/Shapefile.h @@ -487,7 +487,6 @@ class ATL_NO_VTABLE CShapefile : bool GetSorting(vector** indices); public: - ::CCriticalSection ShapefileLock; // geoprocessing methods VARIANT_BOOL FixupShapesCore(VARIANT_BOOL selectedOnly, IShapefile* result); VARIANT_BOOL BufferByDistanceCore(double Distance, LONG nSegments, VARIANT_BOOL SelectedOnly, VARIANT_BOOL MergeResults, IShapefile* result); diff --git a/src/COM classes/Shapefile_Edit.cpp b/src/COM classes/Shapefile_Edit.cpp index a6e91826..9b992e4d 100644 --- a/src/COM classes/Shapefile_Edit.cpp +++ b/src/COM classes/Shapefile_Edit.cpp @@ -1,1177 +1,1172 @@ -//******************************************************************************************************** -//File name: Shapefile.cpp -//Description: Implementation of the CShapefile (see other cpp files as well) -//******************************************************************************************************** -//The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -//you may not use this file except in compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -//ANY KIND, either express or implied. See the License for the specific language governing rights and -//limitations under the License. -// -//The Original Code is MapWindow Open Source. -// -//The Initial Developer of this version of the Original Code is Daniel P. Ames using portions created by -//Utah State University and the Idaho National Engineering and Environmental Lab that were released as -//public domain in March 2004. -// -//Contributor(s): (Open source contributors should list themselves and their modifications here). -// ------------------------------------------------------------------------------------------------------- -// lsu 3-02-2011: split the initial Shapefile.cpp file to make entities of the reasonable size -#pragma once -#include "stdafx.h" -#include "Shapefile.h" -#include "TableClass.h" -#include "Charts.h" -#include "Shape.h" -#include "ShapeHelper.h" - -#pragma region StartEditing - -// ************************************************************ -// StartEditingShapes() -// ************************************************************ -STDMETHODIMP CShapefile::StartEditingShapes(VARIANT_BOOL StartEditTable, ICallback *cBack, VARIANT_BOOL *retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - - if (_appendMode) { - StopAppendMode(); - } - - bool callbackIsNull = (_globalCallback == NULL); - if(cBack != NULL && _globalCallback == NULL) - { - _globalCallback = cBack; - _globalCallback->AddRef(); - } - - if( _table == NULL || _sourceType == sstUninitialized) - { - ErrorMessage(tkSHAPEFILE_UNINITIALIZED); - return S_OK; - } - else if( _isEditingShapes ) - { - *retval = VARIANT_TRUE; - return S_OK; - } - else if (_writing) - { - ErrorMessage(tkSHP_READ_VIOLATION); - return S_OK; - } - - double xMin, xMax, yMin, yMax, zMin, zMax; - this->ClearQTree(&xMin, &xMax, &yMin, &yMax, &zMin, &zMax); - - // reading shapes into memory - IShape * shp = NULL; - _lastErrorCode = tkNO_ERROR; - long percent = 0, newpercent = 0; - - int size = (int)_shapeData.size(); - for( int i = 0; i < size; i++) - { - get_Shape(i, &shp); - - if( _lastErrorCode != tkNO_ERROR ) - { - ErrorMessage(_lastErrorCode); - ReleaseMemoryShapes(); - return S_OK; - } - - _shapeData[i]->shape = shp; - _shapeData[i]->originalIndex = i; - - if(_useQTree) - { - QuickExtentsCore(i, &xMin, &yMin, &xMax, &yMax); - - QTreeNode node; - node.Extent.left = xMin; - node.Extent.right= xMax; - node.Extent.top = yMax; - node.Extent.bottom = yMin; - node.index = i; - _qtree->AddNode(node); - } - - CallbackHelper::Progress(_globalCallback, i, size, "Reading shapes into memory", _key, percent); - } - CallbackHelper::ProgressCompleted(_globalCallback); - - *retval = VARIANT_TRUE; - - // it's used in the disk based mode only - ReleaseRenderingCache(); - - // ------------------------------------------ - // reading table into memory - // ------------------------------------------ - if(StartEditTable != VARIANT_FALSE) - { - StartEditingTable(_globalCallback, retval); - } - - if (*retval == VARIANT_FALSE) - { - ErrorMessage(_table->get_LastErrorCode(&_lastErrorCode)); - ReleaseMemoryShapes(); - } - else - { - _isEditingShapes = TRUE; - } - - if (callbackIsNull) { - _globalCallback = NULL; - } - return S_OK; -} - -#pragma endregion - -#pragma region StopEditing - -// ******************************************************** -// StopEditingShapes() -// ******************************************************** -STDMETHODIMP CShapefile::StopEditingShapes(VARIANT_BOOL ApplyChanges, VARIANT_BOOL StopEditTable, ICallback *cBack, VARIANT_BOOL *retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - - if (!_globalCallback && cBack) - put_GlobalCallback(cBack); - - if( _table == NULL || _sourceType == sstUninitialized) - return S_OK; // don't report anything as StopEditingShapes will be called from Close for any InMemoryShapefile - - if( _isEditingShapes == FALSE ) - { - *retval = VARIANT_TRUE; - return S_OK; - } - - if ( _writing ) - { - ErrorMessage(tkSHP_WRITE_VIOLATION, cBack); - return S_OK; - } - - if ( _sourceType == sstInMemory ) - { - // shapefile wasn't saved before - if(_shpfileName.GetLength() > 0) - { - Save(cBack, retval); - - if (*retval) - { - _isEditingShapes = VARIANT_FALSE; - - if (StopEditTable) - { - StopEditingTable(ApplyChanges, cBack, retval); - } - } - } - *retval = VARIANT_TRUE; - return S_OK; - } - - USES_CONVERSION; - - if( ApplyChanges ) - { - _writing = true; - - // verify Shapefile Integrity - if( VerifyMemShapes(cBack) == FALSE ) - { - // error Code is set in function - } - else - { - _shpfile = _wfreopen(_shpfileName, L"wb+", _shpfile); - _shxfile = _wfreopen(_shxfileName, L"wb+",_shxfile); - - if( _shpfile == NULL || _shxfile == NULL ) - { - if( _shxfile != NULL ) - { - fclose( _shxfile ); - _shxfile = NULL; - - } - if( _shpfile != NULL ) - { - fclose( _shpfile ); - _shpfile = NULL; - ErrorMessage(tkCANT_OPEN_SHP, cBack); - } - } - else - { - // force computation of Extents - VARIANT_BOOL vbretval; - this->RefreshExtents(&vbretval); - - WriteShp(_shpfile,cBack); - WriteShx(_shxfile,cBack); - - _shpfile = _wfreopen(_shpfileName,L"rb+", _shpfile); - _shxfile = _wfreopen(_shxfileName,L"rb+",_shxfile); - - if( _shpfile == NULL || _shxfile == NULL ) - { - if( _shxfile != NULL ) - { - fclose( _shxfile ); - _shxfile = NULL; - ErrorMessage(tkCANT_OPEN_SHX, cBack); - } - if( _shpfile != NULL ) - { - fclose( _shpfile ); - _shpfile = NULL; - ErrorMessage(tkCANT_OPEN_SHP, cBack); - } - } - else - { - _isEditingShapes = FALSE; - ReleaseMemoryShapes(); - *retval = VARIANT_TRUE; - - if(StopEditTable != VARIANT_FALSE) - StopEditingTable(ApplyChanges,cBack,retval); - - // remove disk-based index, it's no longer valid - VARIANT_BOOL spatialIndex; - get_HasSpatialIndex(&spatialIndex); - - if (spatialIndex) { - VARIANT_BOOL vb; - RemoveSpatialIndex(&vb); - - CComBSTR bstr(_shpfileName); - CreateSpatialIndex(bstr, &vb); - } - } - } - } - _writing = false; - } - else - { - // discard the changes - _isEditingShapes = FALSE; - ReleaseMemoryShapes(); - - // reload the shx file - this->ReadShx(); - - if(StopEditTable != VARIANT_FALSE) - { - StopEditingTable(ApplyChanges,cBack,retval); - } - - RestoreShapeRecordsMapping(); - - *retval = VARIANT_TRUE; - } - - return S_OK; -} - -// *********************************************************** -// RestoreShapeRecordsMapping() -// *********************************************************** -void CShapefile::RestoreShapeRecordsMapping() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - // if in memory records still match the disk ones - bool clearRecords = _shpOffsets.size() != _shapeData.size(); - for (size_t i = 0; i < _shapeData.size(); i++) - { - if (_shapeData[i]->originalIndex != i) { - clearRecords = true; - break; - } - } - - // clear in-memory shape records as mapping between disk shapefile and in-memory one is lost - if (clearRecords) - { - for (unsigned int i = 0; i < _shapeData.size(); i++) - delete _shapeData[i]; // all the releasing done in the destructor - _shapeData.clear(); - _shapeData.reserve(_shpOffsets.size()); - for (size_t i = 0; i < _shpOffsets.size(); i++) - { - _shapeData.push_back(new ShapeRecord()); - } - - // reapply categories - long categoriesCount; - _categories->get_Count(&categoriesCount); - if (categoriesCount > 0) { - _categories->ApplyExpressions(); - } - } -} - -#pragma endregion - -#pragma region Operations - -// *********************************************************** -// RegisterNewShape() -// *********************************************************** -// Must be called after inserting or swapping shape in shape vector -void CShapefile::RegisterNewShape(IShape* Shape, long ShapeIndex) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - // shape must have correct underlying data structure - if ((_fastMode ? true : false) != ((CShape*)Shape)->get_fastMode()) - { - ((CShape*)Shape)->put_FastMode(_fastMode ? true : false); - } - - // updating labels and charts - if (_table) - { - double x = 0.0, y = 0.0, rotation = 0.0; - VARIANT_BOOL vbretval; - - VARIANT_BOOL bSynchronized; - _labels->get_Synchronized(&bSynchronized); - - bool chartsExist = ((CCharts*)_charts)->GetChartsExist(); - if (bSynchronized || chartsExist) - { - // position - tkLabelPositioning positioning; - _labels->get_Positioning(&positioning); - - tkLineLabelOrientation orientation; - _labels->get_LineOrientation(&orientation); - - ((CShape*)Shape)->get_LabelPosition(positioning, x, y, rotation, orientation); - } - - if (bSynchronized) - { - // it doesn't make sense to recalculate expression as DBF cells are empty all the same - CComBSTR bstrText(""); - _labels->InsertLabel(ShapeIndex, bstrText, x, y, rotation, -1, &vbretval); - } - - if (chartsExist) - { - if (!_shapeData[ShapeIndex]->chart) - { - _shapeData[ShapeIndex]->chart = new CChartInfo(); - _shapeData[ShapeIndex]->chart->x = x; - _shapeData[ShapeIndex]->chart->y = y; - } - } - } - - _sortingChanged = true; - - // extending the bounds of the shapefile we don't care if the bounds became less - // it's necessary to call RefreshExtents in this case, for zoom to layer working right - if (!ShapeHelper::IsEmpty(Shape)) - { - CComPtr box = NULL; - Shape->get_Extents(&box); - double xm, ym, zm, xM, yM, zM; - box->GetBounds(&xm, &ym, &zm, &xM, &yM, &zM); - - if (_shapeData.size() == 1) - { - _minX = xm; - _maxX = xM; - _minY = ym; - _maxY = yM; - _minZ = zm; - _maxZ = zM; - } - else - { - if (xm < _minX) _minX = xm; - if (xM > _maxX) _maxX = xM; - if (ym < _minY) _minY = ym; - if (yM > _maxY) _maxY = yM; - if (zm < _minZ) _minZ = zm; - if (zM > _maxZ) _maxZ = zM; - } - - if (_useQTree) - { - QTreeNode node; - node.index = ShapeIndex; - node.Extent.left = xm; - node.Extent.right = xM; - node.Extent.top = yM; - node.Extent.bottom = ym; - _qtree->AddNode(node); - } - } -} - -// *********************************************************** -// EditUpdateShape() -// *********************************************************** -// Substitutes one shape with another without formal remove/add call, -// so that attribute table will be intact -STDMETHODIMP CShapefile::EditUpdateShape(long shapeIndex, IShape* shpNew, VARIANT_BOOL *retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - if (!_isEditingShapes) - { - ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); - return S_OK; - } - - if (shapeIndex < 0 || shapeIndex >= (long)_shapeData.size()) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - return S_OK; - } - - ShpfileType shpType; - shpNew->get_ShapeType2D(&shpType); - if (shpType != ShapeUtility::Convert2D(_shpfiletype) && shpType != SHP_NULLSHAPE) - { - ErrorMessage(tkINCOMPATIBLE_SHAPE_TYPE); - return S_OK; - } - - ComHelper::SetRef(shpNew, (IDispatch**)&_shapeData[shapeIndex]->shape, false); - ReregisterShape(shapeIndex); - _shapeData[shapeIndex]->modified(true); - - *retval = VARIANT_TRUE; - return S_OK; - -} - -// *********************************************************** -// UpdateShapeCore() -// *********************************************************** -// should be called when geometry of shape changed -void CShapefile::ReregisterShape(int shapeIndex) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (!_isEditingShapes) return; - - if (shapeIndex < 0 || shapeIndex >= (int)_shapeData.size()) - return; - - IShape* shp = _shapeData[shapeIndex]->shape; - - bool fastMode = _fastMode ? true : false; - if (fastMode != ((CShape*)shp)->get_fastMode()) - { - ((CShape*)shp)->put_FastMode(fastMode); - } - - IExtents * box; - shp->get_Extents(&box); - double xm,ym,zm,xM,yM,zM; - box->GetBounds(&xm,&ym,&zm,&xM,&yM,&zM); - box->Release(); - - if (_shapeData.size() == 1) - { - _minX = xm; - _maxX = xM; - _minY = ym; - _maxY = yM; - _minZ = zm; - _maxZ = zM; - } - else - { - if (xm < _minX) _minX = xm; - if (xM > _maxX) _maxX = xM; - if (ym < _minY) _minY = ym; - if (yM > _maxY) _maxY = yM; - if (zm < _minZ) _minZ = zm; - if (zM > _maxZ) _maxZ = zM; - } - - if(_useQTree) - { - _qtree->RemoveNode(shapeIndex); - - QTreeNode node; - node.index = shapeIndex; - node.Extent.left = xm; - node.Extent.right = xM; - node.Extent.top = yM; - node.Extent.bottom = ym; - _qtree->AddNode(node); - } -} - -// *********************************************************** -// EditInsertShape() -// *********************************************************** -STDMETHODIMP CShapefile::EditInsertShape(IShape *Shape, long *ShapeIndex, VARIANT_BOOL *retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - - if( _table == NULL || _sourceType == sstUninitialized ) - { - ErrorMessage(tkSHAPEFILE_UNINITIALIZED); - return S_OK; - } - - bool canAppend = _appendMode && (*ShapeIndex) >= (long)_shapeData.size(); - - if (!_isEditingShapes && !canAppend) - { - ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); - return S_OK; - } - - VARIANT_BOOL isEditingTable; - _table->get_EditingTable(&isEditingTable); - - if (!isEditingTable && !canAppend) - { - ErrorMessage(tkDBF_NOT_IN_EDIT_MODE); - return S_OK; - } - - if (Shape == NULL) - { - ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); - return S_OK; - } - - ShpfileType shapetype; - Shape->get_ShapeType(&shapetype); - - // MWGIS-91 - bool areEqualTypes = shapetype == _shpfiletype; - if (!areEqualTypes){ - areEqualTypes = ShapeUtility::Convert2D(shapetype) == ShapeUtility::Convert2D(_shpfiletype); - } - - // if( shapetype != SHP_NULLSHAPE && shapetype != _shpfiletype) - if (shapetype != SHP_NULLSHAPE && !areEqualTypes) - { - ErrorMessage(tkINCOMPATIBLE_SHAPEFILE_TYPE); - return S_OK; - } - - if (_appendMode) { - WriteAppendedShape(); - } - - // wrong index will be corrected - if( *ShapeIndex < 0 ) - { - *ShapeIndex = 0; - } - else if( *ShapeIndex > (int)_shapeData.size() ) - { - *ShapeIndex = _shapeData.size(); - } - - _table->EditInsertRow( ShapeIndex, retval ); - - if( *retval == VARIANT_FALSE ) - { - _table->get_LastErrorCode(&_lastErrorCode); - ErrorMessage(_lastErrorCode); - } - else - { - ShapeRecord* data = new ShapeRecord(); - Shape->AddRef(); - data->shape = Shape; - data->modified(true); - _shapeData.insert(_shapeData.begin() + *ShapeIndex, data); - - if (_useQTree && !_qtree) - GenerateQTree(); - - RegisterNewShape(Shape, *ShapeIndex); - - *retval = VARIANT_TRUE; - } - - ((CTableClass*)_table)->set_IndexValue(*ShapeIndex); - - return S_OK; -} - -// ********************************************************************* -// WriteAppendedShape() -// ********************************************************************* -bool CShapefile::WriteAppendedShape() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (!_appendMode || _shapeData.size() == 0) return false; - - if (_shapeData.size() == _appendStartShapeCount) return false; // no shapes were added - - ShapeRecord* record = _shapeData[_shapeData.size() - 1]; - if (!record->shape) return false; - - IShapeWrapper* wrapper = ((CShape*)record->shape)->get_ShapeWrapper(); - if (!wrapper) return false; - - // TODO: calculate based on previous values instead - fseek(_shpfile, 0, SEEK_END); - int offset = ftell(_shpfile); - - // update SHX file - AppendToShx(_shxfile, record->shape, offset); - - // update SHP file - AppendToShpFile(_shpfile, wrapper); - - // update DBF file - ((CTableClass*)_table)->WriteAppendedRow(); - - record->ReleaseShape(); - - return true; -} - -// ********************************************************************* -// EditDeleteShape() -// ********************************************************************* -STDMETHODIMP CShapefile::EditDeleteShape(long ShapeIndex, VARIANT_BOOL *retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; - - if( _table == NULL || _sourceType == sstUninitialized ) - { - ErrorMessage(tkSHAPEFILE_UNINITIALIZED); - } - else if(!_isEditingShapes) - { - ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); - } - else - { - VARIANT_BOOL isEditingTable; - _table->get_EditingTable(&isEditingTable); - - if(!isEditingTable) - { - ErrorMessage(tkDBF_NOT_IN_EDIT_MODE); - } - else if( ShapeIndex < 0 || ShapeIndex >= (int)_shapeData.size() ) - { - ErrorMessage(tkINDEX_OUT_OF_BOUNDS); - } - else - { - VARIANT_BOOL vbretval; - _table->EditDeleteRow( ShapeIndex, &vbretval); - - if(!vbretval) - { - _table->get_LastErrorCode(&_lastErrorCode); - ErrorMessage(_lastErrorCode); - } - else - { - VARIANT_BOOL bSynchronized; - _labels->get_Synchronized(&bSynchronized); - if (bSynchronized) - _labels->RemoveLabel(ShapeIndex, &vbretval); - - delete _shapeData[ShapeIndex]; - _shapeData.erase( _shapeData.begin() + ShapeIndex ); - - _sortingChanged = true; - - // TODO: why haven't we updated QTree? - *retval = VARIANT_TRUE; - } - } - } - return S_OK; -} - -// *********************************************************** -// EditClear() -// *********************************************************** -STDMETHODIMP CShapefile::EditClear(VARIANT_BOOL *retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); - - *retval = VARIANT_FALSE; - - if (_table == NULL || _sourceType == sstUninitialized) - { - return S_OK; - } - - if( _isEditingShapes == FALSE ) - { - ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); - return S_OK; - } - - VARIANT_BOOL isEditingTable; - _table->get_EditingTable(&isEditingTable); - - if( isEditingTable == FALSE ) - { - ErrorMessage(tkDBF_NOT_IN_EDIT_MODE); - } - else - { - // deleting the labels - VARIANT_BOOL bSynchronized; - _labels->get_Synchronized(&bSynchronized); - if (bSynchronized) - { - _labels->Clear(); - } - - _table->EditClear(retval); - if( *retval == VARIANT_FALSE ) - { - _table->get_LastErrorCode(&_lastErrorCode); - ErrorMessage(_lastErrorCode); - } - - for (unsigned int i = 0; i < _shapeData.size(); i++) - { - delete _shapeData[i]; // all the releasing done in the destructor - } - _shapeData.clear(); - - if (_useQTree) - { - this->GenerateQTree(); // will clear it - } - - _sortingChanged = true; - - *retval = VARIANT_TRUE; - } - - return S_OK; -} -#pragma endregion - -#pragma region CacheExtents -// **************************************************************** -// get_CacheExtents() -// **************************************************************** -STDMETHODIMP CShapefile::get_CacheExtents(VARIANT_BOOL * pVal) -{ // The property no longer used AFX_MANAGE_STATE(AfxGetStaticModuleState()); - *pVal = VARIANT_FALSE; - return S_OK; -} - -// **************************************************************** -// put_CacheExtents() -// **************************************************************** -STDMETHODIMP CShapefile::put_CacheExtents(VARIANT_BOOL newVal) +//******************************************************************************************************** +//File name: Shapefile.cpp +//Description: Implementation of the CShapefile (see other cpp files as well) +//******************************************************************************************************** +//The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); +//you may not use this file except in compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +//ANY KIND, either express or implied. See the License for the specific language governing rights and +//limitations under the License. +// +//The Original Code is MapWindow Open Source. +// +//The Initial Developer of this version of the Original Code is Daniel P. Ames using portions created by +//Utah State University and the Idaho National Engineering and Environmental Lab that were released as +//public domain in March 2004. +// +//Contributor(s): (Open source contributors should list themselves and their modifications here). +// ------------------------------------------------------------------------------------------------------- +// lsu 3-02-2011: split the initial Shapefile.cpp file to make entities of the reasonable size +#pragma once +#include "stdafx.h" +#include "Shapefile.h" +#include "TableClass.h" +#include "Charts.h" +#include "Shape.h" +#include "ShapeHelper.h" + +#pragma region StartEditing + +// ************************************************************ +// StartEditingShapes() +// ************************************************************ +STDMETHODIMP CShapefile::StartEditingShapes(VARIANT_BOOL StartEditTable, ICallback *cBack, VARIANT_BOOL *retval) { - // The property no longer used - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - return S_OK; -} - -// ******************************************************************** -// RefreshExtents() -// ******************************************************************** -STDMETHODIMP CShapefile::RefreshExtents(VARIANT_BOOL *retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); - - *retval = VARIANT_TRUE; - if (!_isEditingShapes) return S_OK; - - IExtents * box=NULL; - double Xmin, Ymin, Zmin, Mmin, Xmax, Ymax, Zmax, Mmax; - - _minX = 0.0, _maxX = 0.0; - _minY = 0.0, _maxY = 0.0; - _minZ = 0.0, _maxZ = 0.0; - _minM = 0.0, _maxM = 0.0; - - bool first = true; - for( int i = 0; i < (int)_shapeData.size(); i++ ) - { - if (ShapeHelper::IsEmpty(_shapeData[i]->shape)) - continue; - - CShape* shp = ((CShape*)_shapeData[i]->shape); - shp->get_ExtentsXYZM(Xmin, Ymin, Xmax, Ymax, Zmin, Zmax, Mmin, Mmax); - - // refresh shapefile extents - if (first) - { - _minX = Xmin, _maxX = Xmax; - _minY = Ymin, _maxY = Ymax; - _minZ = Zmin, _maxZ = Zmax; - _minM = Mmin, _maxM = Mmax; - first = false; - } - else - { if( Xmin < _minX ) _minX = Xmin; - if( Xmax > _maxX ) _maxX = Xmax; - if( Ymin < _minY ) _minY = Ymin; - if( Ymax > _maxY ) _maxY = Ymax; - if( Zmin < _minZ ) _minZ = Zmin; - if( Zmax > _maxZ ) _maxZ = Zmax; - if( Mmin < _minM ) _minM = Mmin; - if( Mmax > _maxM ) _maxM = Mmax; - } - } - return S_OK; -} - -// ******************************************************************** -// RefreshShapeExtents() -// ******************************************************************** -STDMETHODIMP CShapefile::RefreshShapeExtents(LONG ShapeId, VARIANT_BOOL *retval) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); - - // The method is no longer used - *retval = VARIANT_TRUE; - return S_OK; -} -#pragma endregion - -#pragma region Utilities -// ******************************************************************** -// ReleaseMemoryShapes() -// ******************************************************************** -BOOL CShapefile::ReleaseMemoryShapes() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - - int size = (int)_shapeData.size(); - for( int i = 0; i < size; i++ ) - { - if (_shapeData[i]->shape) - { - _shapeData[i]->shape->Release(); - _shapeData[i]->shape = NULL; - } - } - return S_OK; -} - -// **************************************************************** -// verifyMemShapes -// **************************************************************** -//Verify Shapefile Integrity -BOOL CShapefile::VerifyMemShapes(ICallback * cBack) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - ShpfileType shapetype; - long numPoints; - long numParts; - IPoint * firstPnt = NULL; - IPoint * lastPnt = NULL; - VARIANT_BOOL vbretval = VARIANT_FALSE; - - if (!_globalCallback && cBack) - { - _globalCallback = cBack; - _globalCallback->AddRef(); - } - - for( int i = 0; i < (int)_shapeData.size(); i++ ) - { - IShape* shp = _shapeData[i]->shape; - if ( !shp ) - continue; - - shp->get_ShapeType(&shapetype); - // MWGIS-91 - bool areEqualTypes = shapetype == _shpfiletype; - if (!areEqualTypes){ - areEqualTypes = ShapeUtility::Convert2D(shapetype) == ShapeUtility::Convert2D(_shpfiletype); - } - shp->get_NumPoints(&numPoints); - shp->get_NumParts(&numParts); - - if (shapetype != SHP_NULLSHAPE && !areEqualTypes) - { - - ErrorMessage(tkINCOMPATIBLE_SHAPE_TYPE); - return FALSE; - } - else if( shapetype == SHP_POINT || shapetype == SHP_POINTZ || shapetype == SHP_POINTM ) - { - if( numPoints == 0 ) - { - ShpfileType tmpshptype = SHP_NULLSHAPE; - shp->put_ShapeType(tmpshptype); - } - } - else if( shapetype == SHP_POLYLINE || shapetype == SHP_POLYLINEZ || shapetype == SHP_POLYLINEM ) - { - if( numPoints < 2 ) - { - ShpfileType tmpshptype = SHP_NULLSHAPE; - shp->put_ShapeType(tmpshptype); - } - else if( numParts == 0 ) - { - long partindex = 0; - shp->InsertPart(0,&partindex,&vbretval); - } - } - else if( shapetype == SHP_POLYGON || shapetype == SHP_POLYGONZ || shapetype == SHP_POLYGONM ) - { - if( numPoints < 3 ) - { - ShpfileType tmpshptype = SHP_NULLSHAPE; - shp->put_ShapeType(tmpshptype); - } - else - { - if( numParts == 0 ) - { - long partindex = 0; - shp->InsertPart(0,&partindex,&vbretval); - numParts = 1; - } - - //force the first and last point of a ring to be the same - long partOffset = 0; - for( int p = 0; p < numParts; p++ ) - { - long startRing; - shp->get_Part(p,&startRing); - long endRing = 0; - if( p == numParts - 1 ) - endRing = numPoints; - else - shp->get_Part(p+1,&endRing); - - if( startRing < 0 || startRing >= numPoints + partOffset ) - startRing = 0; - if( endRing < startRing || endRing >= numPoints + partOffset ) - endRing = numPoints + partOffset; - - shp->get_Point(startRing,&firstPnt); - shp->get_Point(endRing - 1,&lastPnt); - - double x1, y1, z1; - double x2, y2, z2; - - if ( firstPnt && lastPnt ) - { - firstPnt->get_X(&x1); - firstPnt->get_Y(&y1); - firstPnt->get_Z(&z1); - - lastPnt->get_X(&x2); - lastPnt->get_Y(&y2); - lastPnt->get_Z(&z2); - - // make sure first and last point are the same for each part - if( x1 != x2 || y1 != y2 || z1 != z2 ) - { - VARIANT_BOOL retval; - shp->InsertPoint(firstPnt, &endRing, &retval); - for( int t = p+1; t < numParts; t++ ) - { - shp->get_Part(t,&startRing); - shp->put_Part(t,startRing+1); - partOffset++; - } - } - } - if ( firstPnt ) - { - firstPnt->Release(); - firstPnt = NULL; - } - - if ( lastPnt ) - { - lastPnt->Release(); - lastPnt = NULL; - } - } - } - } - else if( shapetype == SHP_MULTIPOINT || shapetype == SHP_MULTIPOINTZ || shapetype == SHP_MULTIPOINTM ) - { - if( numPoints == 0 ) - { - ShpfileType tmpshptype = SHP_NULLSHAPE; - shp->put_ShapeType(tmpshptype); - } - } - } - return TRUE; -} -#pragma endregion - -// **************************************************************** -// get_InteractiveEditing -// **************************************************************** -STDMETHODIMP CShapefile::get_InteractiveEditing(VARIANT_BOOL* pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _isEditingShapes && _interactiveEditing; - return S_OK; -} - -// **************************************************************** -// put_InteractiveEditing -// **************************************************************** -STDMETHODIMP CShapefile::put_InteractiveEditing(VARIANT_BOOL newVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); - if (!_isEditingShapes && newVal) - { - // start edit mode; naturally no interactive editing without it - StartEditingShapes(VARIANT_TRUE, NULL, &_interactiveEditing); - return S_OK; // error code in previous code - } - _interactiveEditing = newVal; // don't stop edit mode; only interactive mode was stopped - return S_OK; -} - -// **************************************************************** -// ReopenFiles -// **************************************************************** -bool CShapefile::ReopenFiles(bool writeMode) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (_sourceType != sstDiskBased) - { - return false; - } - - CStringW mode = writeMode ? L"rb+" : L"rb"; - - FILE* shpfile = _wfopen(_shpfileName, mode); - FILE* shxfile = _wfopen(_shxfileName, mode); - - if (!shpfile || !shxfile) - { - CallbackHelper::ErrorMsg("Failed to reopen shx/shp files."); - fclose(shpfile); - fclose(shxfile); - return false; - } - - fclose(_shpfile); - fclose(_shxfile); - - _shpfile = shpfile; - _shxfile = shxfile; - - return true; -} - -// **************************************************************** -// StartAppendMode -// **************************************************************** -STDMETHODIMP CShapefile::StartAppendMode(VARIANT_BOOL* retVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - - *retVal = VARIANT_FALSE; - - if (_sourceType != sstDiskBased) - { - ErrorMessage(tkAPPEND_MODE_NO_FILE); - return S_OK; - } - - if (!ReopenFiles(true)) - { - // error is reported in function - return S_OK; - } - - _appendStartShapeCount = _shapeData.size(); - - ((CTableClass*)_table)->StartAppendMode(); - - _appendMode = VARIANT_TRUE; - *retVal = VARIANT_TRUE; - - return S_OK; -} - -// **************************************************************** -// StopAppendMode -// **************************************************************** -STDMETHODIMP CShapefile::StopAppendMode() -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - - if (_appendMode ) - { - WriteAppendedShape(); - - // updating shx file length - fseek(_shxfile, 24, SEEK_SET); - int fileLength = HEADER_BYTES_16 + (int)_shapeData.size() * 4; // in 16 bit words - ShapeUtility::WriteBigEndian(_shxfile, fileLength); - - // bounds - fseek(_shxfile, 36, SEEK_SET); - WriteBounds(_shxfile); - fflush(_shxfile); - - // updating shp file length - fseek(_shpfile, 0, SEEK_END); - fileLength = ftell(_shpfile); - fseek(_shpfile, 24, SEEK_SET); - ShapeUtility::WriteBigEndian(_shpfile, fileLength / 2); - - // updating bounds - VARIANT_BOOL retVal; - RefreshExtents(&retVal); - - // bounds - fseek(_shpfile, 36, SEEK_SET); - WriteBounds(_shpfile); - fflush(_shpfile); - - // commit the last DBF record - ((CTableClass*)_table)->StopAppendMode(); - - _appendStartShapeCount = -1; - _appendMode = VARIANT_FALSE; - - ReopenFiles(false); - } - - return S_OK; -} - -// **************************************************************** -// get_AppendMode -// **************************************************************** -STDMETHODIMP CShapefile::get_AppendMode(VARIANT_BOOL* pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - - *pVal = _appendMode; - - return S_OK; -} + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retval = VARIANT_FALSE; + + if (_appendMode) { + StopAppendMode(); + } + + bool callbackIsNull = (_globalCallback == NULL); + if(cBack != NULL && _globalCallback == NULL) + { + _globalCallback = cBack; + _globalCallback->AddRef(); + } + + if( _table == NULL || _sourceType == sstUninitialized) + { + ErrorMessage(tkSHAPEFILE_UNINITIALIZED); + return S_OK; + } + else if( _isEditingShapes ) + { + *retval = VARIANT_TRUE; + return S_OK; + } + else if (_writing) + { + ErrorMessage(tkSHP_READ_VIOLATION); + return S_OK; + } + + double xMin, xMax, yMin, yMax, zMin, zMax; + this->ClearQTree(&xMin, &xMax, &yMin, &yMax, &zMin, &zMax); + + // reading shapes into memory + IShape * shp = NULL; + _lastErrorCode = tkNO_ERROR; + long percent = 0, newpercent = 0; + + int size = (int)_shapeData.size(); + for( int i = 0; i < size; i++) + { + get_Shape(i, &shp); + + if( _lastErrorCode != tkNO_ERROR ) + { + ErrorMessage(_lastErrorCode); + ReleaseMemoryShapes(); + return S_OK; + } + + _shapeData[i]->shape = shp; + _shapeData[i]->originalIndex = i; + + if(_useQTree) + { + QuickExtentsCore(i, &xMin, &yMin, &xMax, &yMax); + + QTreeNode node; + node.Extent.left = xMin; + node.Extent.right= xMax; + node.Extent.top = yMax; + node.Extent.bottom = yMin; + node.index = i; + _qtree->AddNode(node); + } + + CallbackHelper::Progress(_globalCallback, i, size, "Reading shapes into memory", _key, percent); + } + CallbackHelper::ProgressCompleted(_globalCallback); + + *retval = VARIANT_TRUE; + + // it's used in the disk based mode only + ReleaseRenderingCache(); + + // ------------------------------------------ + // reading table into memory + // ------------------------------------------ + if(StartEditTable != VARIANT_FALSE) + { + StartEditingTable(_globalCallback, retval); + } + + if (*retval == VARIANT_FALSE) + { + ErrorMessage(_table->get_LastErrorCode(&_lastErrorCode)); + ReleaseMemoryShapes(); + } + else + { + _isEditingShapes = TRUE; + } + + if (callbackIsNull) { + _globalCallback = NULL; + } + return S_OK; +} + +#pragma endregion + +#pragma region StopEditing + +// ******************************************************** +// StopEditingShapes() +// ******************************************************** +STDMETHODIMP CShapefile::StopEditingShapes(VARIANT_BOOL ApplyChanges, VARIANT_BOOL StopEditTable, ICallback *cBack, VARIANT_BOOL *retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retval = VARIANT_FALSE; + + if (!_globalCallback && cBack) + put_GlobalCallback(cBack); + + if( _table == NULL || _sourceType == sstUninitialized) + return S_OK; // don't report anything as StopEditingShapes will be called from Close for any InMemoryShapefile + + if( _isEditingShapes == FALSE ) + { + *retval = VARIANT_TRUE; + return S_OK; + } + + if ( _writing ) + { + ErrorMessage(tkSHP_WRITE_VIOLATION, cBack); + return S_OK; + } + + if ( _sourceType == sstInMemory ) + { + // shapefile wasn't saved before + if(_shpfileName.GetLength() > 0) + { + Save(cBack, retval); + + if (*retval) + { + _isEditingShapes = VARIANT_FALSE; + + if (StopEditTable) + { + StopEditingTable(ApplyChanges, cBack, retval); + } + } + } + *retval = VARIANT_TRUE; + return S_OK; + } + + USES_CONVERSION; + + if( ApplyChanges ) + { + _writing = true; + + // verify Shapefile Integrity + if( VerifyMemShapes(cBack) == FALSE ) + { + // error Code is set in function + } + else + { + _shpfile = _wfreopen(_shpfileName, L"wb+", _shpfile); + _shxfile = _wfreopen(_shxfileName, L"wb+",_shxfile); + + if( _shpfile == NULL || _shxfile == NULL ) + { + if( _shxfile != NULL ) + { + fclose( _shxfile ); + _shxfile = NULL; + + } + if( _shpfile != NULL ) + { + fclose( _shpfile ); + _shpfile = NULL; + ErrorMessage(tkCANT_OPEN_SHP, cBack); + } + } + else + { + // force computation of Extents + VARIANT_BOOL vbretval; + this->RefreshExtents(&vbretval); + + WriteShp(_shpfile,cBack); + WriteShx(_shxfile,cBack); + + _shpfile = _wfreopen(_shpfileName,L"rb+", _shpfile); + _shxfile = _wfreopen(_shxfileName,L"rb+",_shxfile); + + if( _shpfile == NULL || _shxfile == NULL ) + { + if( _shxfile != NULL ) + { + fclose( _shxfile ); + _shxfile = NULL; + ErrorMessage(tkCANT_OPEN_SHX, cBack); + } + if( _shpfile != NULL ) + { + fclose( _shpfile ); + _shpfile = NULL; + ErrorMessage(tkCANT_OPEN_SHP, cBack); + } + } + else + { + _isEditingShapes = FALSE; + ReleaseMemoryShapes(); + *retval = VARIANT_TRUE; + + if(StopEditTable != VARIANT_FALSE) + StopEditingTable(ApplyChanges,cBack,retval); + + // remove disk-based index, it's no longer valid + VARIANT_BOOL spatialIndex; + get_HasSpatialIndex(&spatialIndex); + + if (spatialIndex) { + VARIANT_BOOL vb; + RemoveSpatialIndex(&vb); + + CComBSTR bstr(_shpfileName); + CreateSpatialIndex(bstr, &vb); + } + } + } + } + _writing = false; + } + else + { + // discard the changes + _isEditingShapes = FALSE; + ReleaseMemoryShapes(); + + // reload the shx file + this->ReadShx(); + + if(StopEditTable != VARIANT_FALSE) + { + StopEditingTable(ApplyChanges,cBack,retval); + } + + RestoreShapeRecordsMapping(); + + *retval = VARIANT_TRUE; + } + + return S_OK; +} + +// *********************************************************** +// RestoreShapeRecordsMapping() +// *********************************************************** +void CShapefile::RestoreShapeRecordsMapping() +{ + // if in memory records still match the disk ones + bool clearRecords = _shpOffsets.size() != _shapeData.size(); + for (size_t i = 0; i < _shapeData.size(); i++) + { + if (_shapeData[i]->originalIndex != i) { + clearRecords = true; + break; + } + } + + // clear in-memory shape records as mapping between disk shapefile and in-memory one is lost + if (clearRecords) + { + for (unsigned int i = 0; i < _shapeData.size(); i++) + delete _shapeData[i]; // all the releasing done in the destructor + _shapeData.clear(); + _shapeData.reserve(_shpOffsets.size()); + for (size_t i = 0; i < _shpOffsets.size(); i++) + { + _shapeData.push_back(new ShapeRecord()); + } + + // reapply categories + long categoriesCount; + _categories->get_Count(&categoriesCount); + if (categoriesCount > 0) { + _categories->ApplyExpressions(); + } + } +} + +#pragma endregion + +#pragma region Operations + +// *********************************************************** +// RegisterNewShape() +// *********************************************************** +// Must be called after inserting or swapping shape in shape vector +void CShapefile::RegisterNewShape(IShape* Shape, long ShapeIndex) +{ + // shape must have correct underlying data structure + if ((_fastMode ? true : false) != ((CShape*)Shape)->get_fastMode()) + { + ((CShape*)Shape)->put_FastMode(_fastMode ? true : false); + } + + // updating labels and charts + if (_table) + { + double x = 0.0, y = 0.0, rotation = 0.0; + VARIANT_BOOL vbretval; + + VARIANT_BOOL bSynchronized; + _labels->get_Synchronized(&bSynchronized); + + bool chartsExist = ((CCharts*)_charts)->GetChartsExist(); + if (bSynchronized || chartsExist) + { + // position + tkLabelPositioning positioning; + _labels->get_Positioning(&positioning); + + tkLineLabelOrientation orientation; + _labels->get_LineOrientation(&orientation); + + ((CShape*)Shape)->get_LabelPosition(positioning, x, y, rotation, orientation); + } + + if (bSynchronized) + { + // it doesn't make sense to recalculate expression as DBF cells are empty all the same + CComBSTR bstrText(""); + _labels->InsertLabel(ShapeIndex, bstrText, x, y, rotation, -1, &vbretval); + } + + if (chartsExist) + { + if (!_shapeData[ShapeIndex]->chart) + { + _shapeData[ShapeIndex]->chart = new CChartInfo(); + _shapeData[ShapeIndex]->chart->x = x; + _shapeData[ShapeIndex]->chart->y = y; + } + } + } + + _sortingChanged = true; + + // extending the bounds of the shapefile we don't care if the bounds became less + // it's necessary to call RefreshExtents in this case, for zoom to layer working right + if (!ShapeHelper::IsEmpty(Shape)) + { + CComPtr box = NULL; + Shape->get_Extents(&box); + double xm, ym, zm, xM, yM, zM; + box->GetBounds(&xm, &ym, &zm, &xM, &yM, &zM); + + if (_shapeData.size() == 1) + { + _minX = xm; + _maxX = xM; + _minY = ym; + _maxY = yM; + _minZ = zm; + _maxZ = zM; + } + else + { + if (xm < _minX) _minX = xm; + if (xM > _maxX) _maxX = xM; + if (ym < _minY) _minY = ym; + if (yM > _maxY) _maxY = yM; + if (zm < _minZ) _minZ = zm; + if (zM > _maxZ) _maxZ = zM; + } + + if (_useQTree) + { + QTreeNode node; + node.index = ShapeIndex; + node.Extent.left = xm; + node.Extent.right = xM; + node.Extent.top = yM; + node.Extent.bottom = ym; + _qtree->AddNode(node); + } + } +} + +// *********************************************************** +// EditUpdateShape() +// *********************************************************** +// Substitutes one shape with another without formal remove/add call, +// so that attribute table will be intact +STDMETHODIMP CShapefile::EditUpdateShape(long shapeIndex, IShape* shpNew, VARIANT_BOOL *retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retval = VARIANT_FALSE; + if (!_isEditingShapes) + { + ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); + return S_OK; + } + + if (shapeIndex < 0 || shapeIndex >= (long)_shapeData.size()) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + return S_OK; + } + + ShpfileType shpType; + shpNew->get_ShapeType2D(&shpType); + if (shpType != ShapeUtility::Convert2D(_shpfiletype) && shpType != SHP_NULLSHAPE) + { + ErrorMessage(tkINCOMPATIBLE_SHAPE_TYPE); + return S_OK; + } + + ComHelper::SetRef(shpNew, (IDispatch**)&_shapeData[shapeIndex]->shape, false); + ReregisterShape(shapeIndex); + _shapeData[shapeIndex]->modified(true); + + *retval = VARIANT_TRUE; + return S_OK; + +} + +// *********************************************************** +// UpdateShapeCore() +// *********************************************************** +// should be called when geometry of shape changed +void CShapefile::ReregisterShape(int shapeIndex) +{ + if (!_isEditingShapes) return; + + if (shapeIndex < 0 || shapeIndex >= (int)_shapeData.size()) + return; + + IShape* shp = _shapeData[shapeIndex]->shape; + + bool fastMode = _fastMode ? true : false; + if (fastMode != ((CShape*)shp)->get_fastMode()) + { + ((CShape*)shp)->put_FastMode(fastMode); + } + + IExtents * box; + shp->get_Extents(&box); + double xm,ym,zm,xM,yM,zM; + box->GetBounds(&xm,&ym,&zm,&xM,&yM,&zM); + box->Release(); + + if (_shapeData.size() == 1) + { + _minX = xm; + _maxX = xM; + _minY = ym; + _maxY = yM; + _minZ = zm; + _maxZ = zM; + } + else + { + if (xm < _minX) _minX = xm; + if (xM > _maxX) _maxX = xM; + if (ym < _minY) _minY = ym; + if (yM > _maxY) _maxY = yM; + if (zm < _minZ) _minZ = zm; + if (zM > _maxZ) _maxZ = zM; + } + + if(_useQTree) + { + _qtree->RemoveNode(shapeIndex); + + QTreeNode node; + node.index = shapeIndex; + node.Extent.left = xm; + node.Extent.right = xM; + node.Extent.top = yM; + node.Extent.bottom = ym; + _qtree->AddNode(node); + } +} + +// *********************************************************** +// EditInsertShape() +// *********************************************************** +STDMETHODIMP CShapefile::EditInsertShape(IShape *Shape, long *ShapeIndex, VARIANT_BOOL *retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retval = VARIANT_FALSE; + + if( _table == NULL || _sourceType == sstUninitialized ) + { + ErrorMessage(tkSHAPEFILE_UNINITIALIZED); + return S_OK; + } + + bool canAppend = _appendMode && (*ShapeIndex) >= (long)_shapeData.size(); + + if (!_isEditingShapes && !canAppend) + { + ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); + return S_OK; + } + + VARIANT_BOOL isEditingTable; + _table->get_EditingTable(&isEditingTable); + + if (!isEditingTable && !canAppend) + { + ErrorMessage(tkDBF_NOT_IN_EDIT_MODE); + return S_OK; + } + + if (Shape == NULL) + { + ErrorMessage(tkUNEXPECTED_NULL_PARAMETER); + return S_OK; + } + + ShpfileType shapetype; + Shape->get_ShapeType(&shapetype); + + // MWGIS-91 + bool areEqualTypes = shapetype == _shpfiletype; + if (!areEqualTypes){ + areEqualTypes = ShapeUtility::Convert2D(shapetype) == ShapeUtility::Convert2D(_shpfiletype); + } + + // if( shapetype != SHP_NULLSHAPE && shapetype != _shpfiletype) + if (shapetype != SHP_NULLSHAPE && !areEqualTypes) + { + ErrorMessage(tkINCOMPATIBLE_SHAPEFILE_TYPE); + return S_OK; + } + + if (_appendMode) { + WriteAppendedShape(); + } + + // wrong index will be corrected + if( *ShapeIndex < 0 ) + { + *ShapeIndex = 0; + } + else if( *ShapeIndex > (int)_shapeData.size() ) + { + *ShapeIndex = _shapeData.size(); + } + + _table->EditInsertRow( ShapeIndex, retval ); + + if( *retval == VARIANT_FALSE ) + { + _table->get_LastErrorCode(&_lastErrorCode); + ErrorMessage(_lastErrorCode); + } + else + { + ShapeRecord* data = new ShapeRecord(); + Shape->AddRef(); + data->shape = Shape; + data->modified(true); + _shapeData.insert(_shapeData.begin() + *ShapeIndex, data); + + if (_useQTree && !_qtree) + GenerateQTree(); + + RegisterNewShape(Shape, *ShapeIndex); + + *retval = VARIANT_TRUE; + } + + ((CTableClass*)_table)->set_IndexValue(*ShapeIndex); + + return S_OK; +} + +// ********************************************************************* +// WriteAppendedShape() +// ********************************************************************* +bool CShapefile::WriteAppendedShape() +{ + if (!_appendMode || _shapeData.size() == 0) return false; + + if (_shapeData.size() == _appendStartShapeCount) return false; // no shapes were added + + ShapeRecord* record = _shapeData[_shapeData.size() - 1]; + if (!record->shape) return false; + + IShapeWrapper* wrapper = ((CShape*)record->shape)->get_ShapeWrapper(); + if (!wrapper) return false; + + // TODO: calculate based on previous values instead + fseek(_shpfile, 0, SEEK_END); + int offset = ftell(_shpfile); + + // update SHX file + AppendToShx(_shxfile, record->shape, offset); + + // update SHP file + AppendToShpFile(_shpfile, wrapper); + + // update DBF file + ((CTableClass*)_table)->WriteAppendedRow(); + + record->ReleaseShape(); + + return true; +} + +// ********************************************************************* +// EditDeleteShape() +// ********************************************************************* +STDMETHODIMP CShapefile::EditDeleteShape(long ShapeIndex, VARIANT_BOOL *retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retval = VARIANT_FALSE; + + if( _table == NULL || _sourceType == sstUninitialized ) + { + ErrorMessage(tkSHAPEFILE_UNINITIALIZED); + } + else if(!_isEditingShapes) + { + ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); + } + else + { + VARIANT_BOOL isEditingTable; + _table->get_EditingTable(&isEditingTable); + + if(!isEditingTable) + { + ErrorMessage(tkDBF_NOT_IN_EDIT_MODE); + } + else if( ShapeIndex < 0 || ShapeIndex >= (int)_shapeData.size() ) + { + ErrorMessage(tkINDEX_OUT_OF_BOUNDS); + } + else + { + VARIANT_BOOL vbretval; + _table->EditDeleteRow( ShapeIndex, &vbretval); + + if(!vbretval) + { + _table->get_LastErrorCode(&_lastErrorCode); + ErrorMessage(_lastErrorCode); + } + else + { + VARIANT_BOOL bSynchronized; + _labels->get_Synchronized(&bSynchronized); + if (bSynchronized) + _labels->RemoveLabel(ShapeIndex, &vbretval); + + delete _shapeData[ShapeIndex]; + _shapeData.erase( _shapeData.begin() + ShapeIndex ); + + _sortingChanged = true; + + // TODO: why haven't we updated QTree? + *retval = VARIANT_TRUE; + } + } + } + return S_OK; +} + +// *********************************************************** +// EditClear() +// *********************************************************** +STDMETHODIMP CShapefile::EditClear(VARIANT_BOOL *retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *retval = VARIANT_FALSE; + + if (_table == NULL || _sourceType == sstUninitialized) + { + return S_OK; + } + + if( _isEditingShapes == FALSE ) + { + ErrorMessage(tkSHPFILE_NOT_IN_EDIT_MODE); + return S_OK; + } + + VARIANT_BOOL isEditingTable; + _table->get_EditingTable(&isEditingTable); + + if( isEditingTable == FALSE ) + { + ErrorMessage(tkDBF_NOT_IN_EDIT_MODE); + } + else + { + // deleting the labels + VARIANT_BOOL bSynchronized; + _labels->get_Synchronized(&bSynchronized); + if (bSynchronized) + { + _labels->Clear(); + } + + _table->EditClear(retval); + if( *retval == VARIANT_FALSE ) + { + _table->get_LastErrorCode(&_lastErrorCode); + ErrorMessage(_lastErrorCode); + } + + for (unsigned int i = 0; i < _shapeData.size(); i++) + { + delete _shapeData[i]; // all the releasing done in the destructor + } + _shapeData.clear(); + + if (_useQTree) + { + this->GenerateQTree(); // will clear it + } + + _sortingChanged = true; + + *retval = VARIANT_TRUE; + } + + return S_OK; +} +#pragma endregion + +#pragma region CacheExtents +// **************************************************************** +// get_CacheExtents() +// **************************************************************** +STDMETHODIMP CShapefile::get_CacheExtents(VARIANT_BOOL * pVal) +{ + // The property no longer used + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *pVal = VARIANT_FALSE; + return S_OK; +} + +// **************************************************************** +// put_CacheExtents() +// **************************************************************** +STDMETHODIMP CShapefile::put_CacheExtents(VARIANT_BOOL newVal) +{ + // The property no longer used + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + return S_OK; +} + +// ******************************************************************** +// RefreshExtents() +// ******************************************************************** +STDMETHODIMP CShapefile::RefreshExtents(VARIANT_BOOL *retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + *retval = VARIANT_TRUE; + if (!_isEditingShapes) return S_OK; + + IExtents * box=NULL; + double Xmin, Ymin, Zmin, Mmin, Xmax, Ymax, Zmax, Mmax; + + _minX = 0.0, _maxX = 0.0; + _minY = 0.0, _maxY = 0.0; + _minZ = 0.0, _maxZ = 0.0; + _minM = 0.0, _maxM = 0.0; + + bool first = true; + for( int i = 0; i < (int)_shapeData.size(); i++ ) + { + if (ShapeHelper::IsEmpty(_shapeData[i]->shape)) + continue; + + CShape* shp = ((CShape*)_shapeData[i]->shape); + shp->get_ExtentsXYZM(Xmin, Ymin, Xmax, Ymax, Zmin, Zmax, Mmin, Mmax); + + // refresh shapefile extents + if (first) + { + _minX = Xmin, _maxX = Xmax; + _minY = Ymin, _maxY = Ymax; + _minZ = Zmin, _maxZ = Zmax; + _minM = Mmin, _maxM = Mmax; + first = false; + } + else + { if( Xmin < _minX ) _minX = Xmin; + if( Xmax > _maxX ) _maxX = Xmax; + if( Ymin < _minY ) _minY = Ymin; + if( Ymax > _maxY ) _maxY = Ymax; + if( Zmin < _minZ ) _minZ = Zmin; + if( Zmax > _maxZ ) _maxZ = Zmax; + if( Mmin < _minM ) _minM = Mmin; + if( Mmax > _maxM ) _maxM = Mmax; + } + } + return S_OK; +} + +// ******************************************************************** +// RefreshShapeExtents() +// ******************************************************************** +STDMETHODIMP CShapefile::RefreshShapeExtents(LONG ShapeId, VARIANT_BOOL *retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + // The method is no longer used + *retval = VARIANT_TRUE; + return S_OK; +} +#pragma endregion + +#pragma region Utilities +// ******************************************************************** +// ReleaseMemoryShapes() +// ******************************************************************** +BOOL CShapefile::ReleaseMemoryShapes() +{ + + int size = (int)_shapeData.size(); + for( int i = 0; i < size; i++ ) + { + if (_shapeData[i]->shape) + { + _shapeData[i]->shape->Release(); + _shapeData[i]->shape = NULL; + } + } + return S_OK; +} + +// **************************************************************** +// verifyMemShapes +// **************************************************************** +//Verify Shapefile Integrity +BOOL CShapefile::VerifyMemShapes(ICallback * cBack) +{ + ShpfileType shapetype; + long numPoints; + long numParts; + IPoint * firstPnt = NULL; + IPoint * lastPnt = NULL; + VARIANT_BOOL vbretval = VARIANT_FALSE; + + if (!_globalCallback && cBack) + { + _globalCallback = cBack; + _globalCallback->AddRef(); + } + + for( int i = 0; i < (int)_shapeData.size(); i++ ) + { + IShape* shp = _shapeData[i]->shape; + if ( !shp ) + continue; + + shp->get_ShapeType(&shapetype); + // MWGIS-91 + bool areEqualTypes = shapetype == _shpfiletype; + if (!areEqualTypes){ + areEqualTypes = ShapeUtility::Convert2D(shapetype) == ShapeUtility::Convert2D(_shpfiletype); + } + shp->get_NumPoints(&numPoints); + shp->get_NumParts(&numParts); + + if (shapetype != SHP_NULLSHAPE && !areEqualTypes) + { + + ErrorMessage(tkINCOMPATIBLE_SHAPE_TYPE); + return FALSE; + } + else if( shapetype == SHP_POINT || shapetype == SHP_POINTZ || shapetype == SHP_POINTM ) + { + if( numPoints == 0 ) + { + ShpfileType tmpshptype = SHP_NULLSHAPE; + shp->put_ShapeType(tmpshptype); + } + } + else if( shapetype == SHP_POLYLINE || shapetype == SHP_POLYLINEZ || shapetype == SHP_POLYLINEM ) + { + if( numPoints < 2 ) + { + ShpfileType tmpshptype = SHP_NULLSHAPE; + shp->put_ShapeType(tmpshptype); + } + else if( numParts == 0 ) + { + long partindex = 0; + shp->InsertPart(0,&partindex,&vbretval); + } + } + else if( shapetype == SHP_POLYGON || shapetype == SHP_POLYGONZ || shapetype == SHP_POLYGONM ) + { + if( numPoints < 3 ) + { + ShpfileType tmpshptype = SHP_NULLSHAPE; + shp->put_ShapeType(tmpshptype); + } + else + { + if( numParts == 0 ) + { + long partindex = 0; + shp->InsertPart(0,&partindex,&vbretval); + numParts = 1; + } + + //force the first and last point of a ring to be the same + long partOffset = 0; + for( int p = 0; p < numParts; p++ ) + { + long startRing; + shp->get_Part(p,&startRing); + long endRing = 0; + if( p == numParts - 1 ) + endRing = numPoints; + else + shp->get_Part(p+1,&endRing); + + if( startRing < 0 || startRing >= numPoints + partOffset ) + startRing = 0; + if( endRing < startRing || endRing >= numPoints + partOffset ) + endRing = numPoints + partOffset; + + shp->get_Point(startRing,&firstPnt); + shp->get_Point(endRing - 1,&lastPnt); + + double x1, y1, z1; + double x2, y2, z2; + + if ( firstPnt && lastPnt ) + { + firstPnt->get_X(&x1); + firstPnt->get_Y(&y1); + firstPnt->get_Z(&z1); + + lastPnt->get_X(&x2); + lastPnt->get_Y(&y2); + lastPnt->get_Z(&z2); + + // make sure first and last point are the same for each part + if( x1 != x2 || y1 != y2 || z1 != z2 ) + { + VARIANT_BOOL retval; + shp->InsertPoint(firstPnt, &endRing, &retval); + for( int t = p+1; t < numParts; t++ ) + { + shp->get_Part(t,&startRing); + shp->put_Part(t,startRing+1); + partOffset++; + } + } + } + if ( firstPnt ) + { + firstPnt->Release(); + firstPnt = NULL; + } + + if ( lastPnt ) + { + lastPnt->Release(); + lastPnt = NULL; + } + } + } + } + else if( shapetype == SHP_MULTIPOINT || shapetype == SHP_MULTIPOINTZ || shapetype == SHP_MULTIPOINTM ) + { + if( numPoints == 0 ) + { + ShpfileType tmpshptype = SHP_NULLSHAPE; + shp->put_ShapeType(tmpshptype); + } + } + } + return TRUE; +} +#pragma endregion + +// **************************************************************** +// get_InteractiveEditing +// **************************************************************** +STDMETHODIMP CShapefile::get_InteractiveEditing(VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *pVal = _isEditingShapes && _interactiveEditing; + return S_OK; +} + +// **************************************************************** +// put_InteractiveEditing +// **************************************************************** +STDMETHODIMP CShapefile::put_InteractiveEditing(VARIANT_BOOL newVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (!_isEditingShapes && newVal) + { + // start edit mode; naturally no interactive editing without it + StartEditingShapes(VARIANT_TRUE, NULL, &_interactiveEditing); + return S_OK; // error code in previous code + } + _interactiveEditing = newVal; // don't stop edit mode; only interactive mode was stopped + return S_OK; +} + +// **************************************************************** +// ReopenFiles +// **************************************************************** +bool CShapefile::ReopenFiles(bool writeMode) +{ + if (_sourceType != sstDiskBased) + { + return false; + } + + CStringW mode = writeMode ? L"rb+" : L"rb"; + + FILE* shpfile = _wfopen(_shpfileName, mode); + FILE* shxfile = _wfopen(_shxfileName, mode); + + if (!shpfile || !shxfile) + { + CallbackHelper::ErrorMsg("Failed to reopen shx/shp files."); + fclose(shpfile); + fclose(shxfile); + return false; + } + + fclose(_shpfile); + fclose(_shxfile); + + _shpfile = shpfile; + _shxfile = shxfile; + + return true; +} + +// **************************************************************** +// StartAppendMode +// **************************************************************** +STDMETHODIMP CShapefile::StartAppendMode(VARIANT_BOOL* retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + *retVal = VARIANT_FALSE; + + if (_sourceType != sstDiskBased) + { + ErrorMessage(tkAPPEND_MODE_NO_FILE); + return S_OK; + } + + if (!ReopenFiles(true)) + { + // error is reported in function + return S_OK; + } + + _appendStartShapeCount = _shapeData.size(); + + ((CTableClass*)_table)->StartAppendMode(); + + _appendMode = VARIANT_TRUE; + *retVal = VARIANT_TRUE; + + return S_OK; +} + +// **************************************************************** +// StopAppendMode +// **************************************************************** +STDMETHODIMP CShapefile::StopAppendMode() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + if (_appendMode ) + { + WriteAppendedShape(); + + // updating shx file length + fseek(_shxfile, 24, SEEK_SET); + int fileLength = HEADER_BYTES_16 + (int)_shapeData.size() * 4; // in 16 bit words + ShapeUtility::WriteBigEndian(_shxfile, fileLength); + + // bounds + fseek(_shxfile, 36, SEEK_SET); + WriteBounds(_shxfile); + fflush(_shxfile); + + // updating shp file length + fseek(_shpfile, 0, SEEK_END); + fileLength = ftell(_shpfile); + fseek(_shpfile, 24, SEEK_SET); + ShapeUtility::WriteBigEndian(_shpfile, fileLength / 2); + + // updating bounds + VARIANT_BOOL retVal; + RefreshExtents(&retVal); + + // bounds + fseek(_shpfile, 36, SEEK_SET); + WriteBounds(_shpfile); + fflush(_shpfile); + + // commit the last DBF record + ((CTableClass*)_table)->StopAppendMode(); + + _appendStartShapeCount = -1; + _appendMode = VARIANT_FALSE; + + ReopenFiles(false); + } + + return S_OK; +} + +// **************************************************************** +// get_AppendMode +// **************************************************************** +STDMETHODIMP CShapefile::get_AppendMode(VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + *pVal = _appendMode; + + return S_OK; +} diff --git a/src/COM classes/Shapefile_Geoprocessing.cpp b/src/COM classes/Shapefile_Geoprocessing.cpp index c730a43e..4ddde33a 100644 --- a/src/COM classes/Shapefile_Geoprocessing.cpp +++ b/src/COM classes/Shapefile_Geoprocessing.cpp @@ -80,11 +80,6 @@ void CShapefile::InsertShapesVector(IShapefile* sf, vector& vShapes, IShapefile* sfSubject, long subjectId, std::map* fieldMapSubject, IShapefile* sfClip, long clipId, std::map* fieldMapClip) { - if (!sf || !sfSubject) return; - - CSingleLock sfLock(&((CShapefile*) sf)->ShapefileLock, TRUE); - CSingleLock sfSubjectLock(&((CShapefile*) sfSubject)->ShapefileLock, TRUE); - long numFieldSubject, numFieldsClip; sfSubject->get_NumFields(&numFieldSubject); if (sfClip) @@ -183,10 +178,6 @@ void CShapefile::InsertShapesVector(IShapefile* sf, vector& vShapes, // initShapeIndex - the index of shape to copy the attribute from bool InsertGeosGeometry(IShapefile* sfTarget, GEOSGeometry* gsNew, IShapefile* sfSouce, int initShapeIndex) { - if (!sfTarget || !sfSouce) return false; - - CSingleLock sfTargetLock(&((CShapefile*)sfTarget)->ShapefileLock, TRUE); - CSingleLock sfSourceLock(&((CShapefile*)sfSouce)->ShapefileLock, TRUE); if (gsNew) { ShpfileType shpType; @@ -229,10 +220,6 @@ bool InsertGeosGeometry(IShapefile* sfTarget, GEOSGeometry* gsNew, IShapefile* s // The row index of attribute table are taken from the key property of the shape void CopyShape(IShapefile* sfSource, IShape* shp, IShapefile* sfResult) { - if (!sfSource || !sfResult) return; - - CSingleLock sfSourceLock(&((CShapefile*)sfSource)->ShapefileLock, TRUE); - CSingleLock sfResultLock(&((CShapefile*)sfResult)->ShapefileLock, TRUE); if (shp) { USES_CONVERSION; @@ -293,7 +280,6 @@ STDMETHODIMP CShapefile::SelectByShapefile(IShapefile* sf, tkSpatialRelation Rel { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock mySfLock(&ShapefileLock, TRUE); USES_CONVERSION; *retval = VARIANT_FALSE; @@ -309,8 +295,6 @@ STDMETHODIMP CShapefile::SelectByShapefile(IShapefile* sf, tkSpatialRelation Rel return S_OK; } - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - long _numShapes2; const long _numShapes1 = _shapeData.size(); sf->get_NumShapes(&_numShapes2); @@ -452,7 +436,6 @@ STDMETHODIMP CShapefile::SelectByShapefile(IShapefile* sf, tkSpatialRelation Rel VARIANT_BOOL CShapefile::SelectShapesAlt(IExtents* BoundBox, double Tolerance, SelectMode SelectMode, VARIANT* arr) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); double xMin, xMax, yMin, yMax, zMin, zMax; BoundBox->GetBounds(&xMin, &yMin, &zMin, &xMax, &yMax, &zMax); @@ -524,9 +507,6 @@ VARIANT_BOOL CShapefile::SelectShapesAlt(IExtents* BoundBox, double Tolerance, S STDMETHODIMP CShapefile::Dissolve(long FieldIndex, VARIANT_BOOL SelectedOnly, IShapefile** sf) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - if (!*sf) return S_OK; - CSingleLock sfLock(&((CShapefile*)*sf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); DissolveCore(FieldIndex, SelectedOnly, nullptr, sf); return S_OK; } @@ -538,9 +518,6 @@ STDMETHODIMP CShapefile::DissolveWithStats(long FieldIndex, VARIANT_BOOL Selecte IFieldStatOperations* statOperations, IShapefile** sf) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - if (!*sf) return S_OK; - CSingleLock sfLock(&((CShapefile*)*sf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); DissolveCore(FieldIndex, SelectedOnly, statOperations, sf); return S_OK; } @@ -553,9 +530,6 @@ STDMETHODIMP CShapefile::DissolveWithStats(long FieldIndex, VARIANT_BOOL Selecte void CShapefile::DissolveCore(long FieldIndex, VARIANT_BOOL SelectedOnly, IFieldStatOperations* operations, IShapefile** sf) { - if (!*sf) return; - CSingleLock sfLock(&((CShapefile*)*sf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); // ---------------------------------------------- // Validation // ---------------------------------------------- @@ -646,9 +620,6 @@ char* GetStatOperationName(tkFieldStatOperation op) void CShapefile::CalculateFieldStats(map*>& fieldMap, IFieldStatOperations* ioperations, IShapefile* sf) { - if (!sf) return; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); // -------------------------------------------- // validating operations // -------------------------------------------- @@ -872,9 +843,6 @@ void CShapefile::CalculateFieldStats(map*>& fieldMap, IFieldSta void CShapefile::DissolveGEOS(long FieldIndex, VARIANT_BOOL SelectedOnly, IFieldStatOperations* operations, IShapefile* sf) { - if (!sf) return; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); map*> fieldMap; // index in output, indices in input map*> indicesMap; // value in input, indices in input map*> shapeMap; @@ -1006,9 +974,6 @@ void CShapefile::DissolveGEOS(long FieldIndex, VARIANT_BOOL SelectedOnly, IField void CShapefile::DissolveClipper(long FieldIndex, VARIANT_BOOL SelectedOnly, IFieldStatOperations* operations, IShapefile* sf) { - if (!sf) return; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); map*> fieldMap; // index in output, indices in input map*> indicesMap; // value in input, indices in input map shapeMap; @@ -1148,7 +1113,6 @@ STDMETHODIMP CShapefile::AggregateShapesWithStats(VARIANT_BOOL SelectedOnly, LON IFieldStatOperations* statOperations, IShapefile** retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); AggregateShapesCore(SelectedOnly, FieldIndex, statOperations, retval); return S_OK; } @@ -1159,7 +1123,6 @@ STDMETHODIMP CShapefile::AggregateShapesWithStats(VARIANT_BOOL SelectedOnly, LON STDMETHODIMP CShapefile::AggregateShapes(VARIANT_BOOL SelectedOnly, LONG FieldIndex, IShapefile** retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); AggregateShapesCore(SelectedOnly, FieldIndex, nullptr, retval); return S_OK; } @@ -1171,9 +1134,6 @@ STDMETHODIMP CShapefile::AggregateShapes(VARIANT_BOOL SelectedOnly, LONG FieldIn void CShapefile::AggregateShapesCore(VARIANT_BOOL SelectedOnly, LONG FieldIndex, IFieldStatOperations* operations, IShapefile** retval) { - if (!*retval) return; - CSingleLock sfLock(&((CShapefile*)*retval)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); long numFields; this->get_NumFields(&numFields); @@ -1422,10 +1382,6 @@ STDMETHODIMP CShapefile::BufferByDistance(double Distance, LONG nSegments, VARIA VARIANT_BOOL MergeResults, IShapefile** sf) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - if (!*sf) return S_OK; - - CSingleLock sfLock(&((CShapefile*) *sf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); if (MergeResults) { @@ -1464,9 +1420,6 @@ STDMETHODIMP CShapefile::BufferByDistance(double Distance, LONG nSegments, VARIA VARIANT_BOOL CShapefile::BufferByDistanceCore(double Distance, LONG nSegments, VARIANT_BOOL SelectedOnly, VARIANT_BOOL MergeResults, IShapefile* sf) { - if (!sf) return VARIANT_FALSE; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); // ------------------------------------------- // validating // ------------------------------------------- @@ -1593,7 +1546,6 @@ STDMETHODIMP CShapefile::Difference(VARIANT_BOOL SelectedOnlySubject, IShapefile VARIANT_BOOL SelectedOnlyOverlay, IShapefile** retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); DoClipOperation(SelectedOnlySubject, sfOverlay, SelectedOnlyOverlay, retval, clDifference); return S_OK; } @@ -1605,7 +1557,6 @@ STDMETHODIMP CShapefile::Clip(VARIANT_BOOL SelectedOnlySubject, IShapefile* sfOv IShapefile** retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); DoClipOperation(SelectedOnlySubject, sfOverlay, SelectedOnlyOverlay, retval, clClip); // enumeration should be repaired return S_OK; @@ -1619,7 +1570,6 @@ STDMETHODIMP CShapefile::GetIntersection(VARIANT_BOOL SelectedOnlyOfThis, IShape IShapefile** retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); DoClipOperation(SelectedOnlyOfThis, sf, SelectedOnly, retval, clIntersection, fileType); return S_OK; } @@ -1631,7 +1581,6 @@ STDMETHODIMP CShapefile::SymmDifference(VARIANT_BOOL SelectedOnlySubject, IShape VARIANT_BOOL SelectedOnlyOverlay, IShapefile** retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); DoClipOperation(SelectedOnlySubject, sfOverlay, SelectedOnlyOverlay, retval, clSymDifference); // enumeration should be repaired return S_OK; @@ -1644,7 +1593,6 @@ STDMETHODIMP CShapefile::Union(VARIANT_BOOL SelectedOnlySubject, IShapefile* sfO VARIANT_BOOL SelectedOnlyOverlay, IShapefile** retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); DoClipOperation(SelectedOnlySubject, sfOverlay, SelectedOnlyOverlay, retval, clUnion); return S_OK; } @@ -1725,7 +1673,6 @@ CString GetClipOperationName(tkClipOperation operation) bool CShapefile::ValidateClippingOutputType(ShpfileType type1, ShpfileType type2, ShpfileType returnType, tkClipOperation operation) { - CSingleLock sfLock(&ShapefileLock, TRUE); switch (operation) { case clSymDifference: @@ -1823,9 +1770,6 @@ void CShapefile::DoClipOperation(VARIANT_BOOL SelectedOnlySubject, IShapefile* s return; } - CSingleLock sfOverlayLock(&((CShapefile*)sfOverlay)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); - ShpfileType type2; const ShpfileType type1 = _shpfiletype; @@ -1996,11 +1940,6 @@ void CShapefile::DoClipOperation(VARIANT_BOOL SelectedOnlySubject, IShapefile* s void CShapefile::ClipGEOS(VARIANT_BOOL SelectedOnlySubject, IShapefile* sfOverlay, VARIANT_BOOL SelectedOnlyOverlay, IShapefile* sfResult) { - if (!sfOverlay || !sfResult) return; - - CSingleLock sfOverlayLock(&((CShapefile*)sfOverlay)->ShapefileLock, TRUE); - CSingleLock sfResultLock(&((CShapefile*)sfResult)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); QTree* qTree = ((CShapefile*)sfOverlay)->GetTempQTree(); long numShapesSubject, numShapesClip; @@ -2100,11 +2039,6 @@ void CShapefile::ClipGEOS(VARIANT_BOOL SelectedOnlySubject, IShapefile* sfOverla void CShapefile::ClipClipper(VARIANT_BOOL SelectedOnlySubject, IShapefile* sfOverlay, VARIANT_BOOL SelectedOnlyOverlay, IShapefile* sfResult) { - if (!sfOverlay || !sfResult) return; - - CSingleLock sfOverlayLock(&((CShapefile*)sfOverlay)->ShapefileLock, TRUE); - CSingleLock sfResultLock(&((CShapefile*)sfResult)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); QTree* qTree = ((CShapefile*)sfOverlay)->GetTempQTree(); long numShapesSubject, numShapesClip; @@ -2246,11 +2180,6 @@ void CShapefile::IntersectionGEOS(VARIANT_BOOL SelectedOnlySubject, IShapefile* std::set* subjectShapesToSkip, std::set* clippingShapesToSkip) { - if (!sfClip || !sfResult) return; - - CSingleLock sfClipLock(&((CShapefile*)sfClip)->ShapefileLock, TRUE); - CSingleLock sfResultLock(&((CShapefile*)sfResult)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); QTree* qTree = ((CShapefile*)sfClip)->GetTempQTree(); long numShapesSubject, numShapesClip; @@ -2331,9 +2260,6 @@ IShapefile* CShapefile::IntersectionClipperNoAttributes(VARIANT_BOOL SelectedOnl if (!sfClip) return nullptr; - CSingleLock sfLock(&((CShapefile*)sfClip)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); - IShapefile* sfResult = nullptr; this->Clone(&sfResult); @@ -2368,11 +2294,6 @@ void CShapefile::IntersectionClipper(VARIANT_BOOL SelectedOnlySubject, IShapefil std::set* subjectShapesToSkip, std::set* clippingShapesToSkip) { - if (!sfClip || !sfResult) return; - - CSingleLock sfClipLock(&((CShapefile*)sfClip)->ShapefileLock, TRUE); - CSingleLock sfResultLock(&((CShapefile*)sfResult)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); QTree* qTree = ((CShapefile*)sfClip)->GetTempQTree(); long numShapesSubject, numShapesClip; @@ -2569,13 +2490,6 @@ void CShapefile::DifferenceGEOS(IShapefile* sfSubject, VARIANT_BOOL SelectedOnly VARIANT_BOOL SelectedOnlyOverlay, IShapefile* sfResult, map* fieldMap, set* shapesToSkip) { - if (!sfOverlay || !sfSubject || !sfResult) return; - - CSingleLock sfOverlayLock(&((CShapefile*)sfOverlay)->ShapefileLock, TRUE); - CSingleLock sfSubjectLock(&((CShapefile*)sfSubject)->ShapefileLock, TRUE); - CSingleLock sfResultLock(&((CShapefile*)sfResult)->ShapefileLock, TRUE); - - CSingleLock sfLock(&ShapefileLock, TRUE); QTree* qTree = ((CShapefile*)sfOverlay)->GetTempQTree(); long numShapesSubject, numShapesClip; @@ -2695,7 +2609,6 @@ void CShapefile::DifferenceGEOS(IShapefile* sfSubject, VARIANT_BOOL SelectedOnly #ifdef SERIALIZE_POLYGONS void SerializePolygon(ofstream& out, ClipperLib::Polygons* poly) { - CSingleLock sfLock(&ShapefileLock, TRUE); if (poly && out.good()) { out.precision(14); @@ -2730,12 +2643,6 @@ void CShapefile::DifferenceClipper(IShapefile* sfSubject, VARIANT_BOOL SelectedO VARIANT_BOOL SelectedOnlyClip, IShapefile* sfResult, map* fieldMap, set* shapesToSkip) { - if (!sfClip || !sfSubject || !sfResult) return; - - CSingleLock sfClipLock(&((CShapefile*)sfClip)->ShapefileLock, TRUE); - CSingleLock sfSubjectLock(&((CShapefile*)sfSubject)->ShapefileLock, TRUE); - CSingleLock sfResultLock(&((CShapefile*)sfResult)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); QTree* qTree = ((CShapefile*)sfClip)->GetTempQTree(); long numShapesSubject, numShapesClip; @@ -2903,7 +2810,6 @@ void CShapefile::DifferenceClipper(IShapefile* sfSubject, VARIANT_BOOL SelectedO STDMETHODIMP CShapefile::get_GeometryEngine(tkGeometryEngine* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); *pVal = _geometryEngine; return S_OK; } @@ -2911,7 +2817,6 @@ STDMETHODIMP CShapefile::get_GeometryEngine(tkGeometryEngine* pVal) STDMETHODIMP CShapefile::put_GeometryEngine(tkGeometryEngine newVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); _geometryEngine = newVal; return S_OK; } @@ -2927,7 +2832,6 @@ STDMETHODIMP CShapefile::put_GeometryEngine(tkGeometryEngine newVal) STDMETHODIMP CShapefile::PointInShape(LONG ShapeIndex, DOUBLE x, DOUBLE y, VARIANT_BOOL* retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); if (ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) { @@ -3083,7 +2987,6 @@ STDMETHODIMP CShapefile::PointInShape(LONG ShapeIndex, DOUBLE x, DOUBLE y, VARIA STDMETHODIMP CShapefile::PointInShapefile(DOUBLE x, DOUBLE y, LONG* ShapeIndex) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); const int nShapeCount = _polySf.size(); for (int nShape = nShapeCount - 1; nShape >= 0; nShape--) @@ -3176,7 +3079,6 @@ STDMETHODIMP CShapefile::PointInShapefile(DOUBLE x, DOUBLE y, LONG* ShapeIndex) STDMETHODIMP CShapefile::BeginPointInShapefile(VARIANT_BOOL* retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); if (_writing) { //AfxMessageBox("Can't read"); @@ -3237,7 +3139,6 @@ STDMETHODIMP CShapefile::BeginPointInShapefile(VARIANT_BOOL* retval) STDMETHODIMP CShapefile::EndPointInShapefile() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); _polySf.clear(); @@ -3255,14 +3156,11 @@ VARIANT_BOOL CShapefile::ExplodeShapesCore(VARIANT_BOOL SelectedOnly, IShapefile // ---------------------------------------------- // Validation // ---------------------------------------------- - if (!result || !ValidateInput(this, "ExplodeShapes", "this", SelectedOnly)) + if (!ValidateInput(this, "ExplodeShapes", "this", SelectedOnly)) { return VARIANT_FALSE; } - CSingleLock sfResultLock(&((CShapefile*)result)->ShapefileLock, TRUE); - CSingleLock sfLock(&ShapefileLock, TRUE); - // ---------------------------------------------- // Processing // ---------------------------------------------- @@ -3328,7 +3226,6 @@ VARIANT_BOOL CShapefile::ExplodeShapesCore(VARIANT_BOOL SelectedOnly, IShapefile STDMETHODIMP CShapefile::ExplodeShapes(VARIANT_BOOL SelectedOnly, IShapefile** retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); Clone(retval); @@ -3349,14 +3246,11 @@ VARIANT_BOOL CShapefile::ExportSelectionCore(IShapefile* result) // ---------------------------------------------- // Validation // ---------------------------------------------- - if (!result || !ValidateInput(this, "Sort", "this", false)) + if (!ValidateInput(this, "Sort", "this", false)) { return VARIANT_FALSE; } - CSingleLock sfResultLock(&((CShapefile*)result)->ShapefileLock, TRUE); - CSingleLock sfLock(&ShapefileLock, TRUE); - // ---------------------------------------------- // Processing // ---------------------------------------------- @@ -3425,7 +3319,6 @@ VARIANT_BOOL CShapefile::ExportSelectionCore(IShapefile* result) STDMETHODIMP CShapefile::ExportSelection(IShapefile** retval) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); Clone(retval); @@ -3446,8 +3339,6 @@ STDMETHODIMP CShapefile::Sort(LONG FieldIndex, VARIANT_BOOL Ascending, IShapefil AFX_MANAGE_STATE(AfxGetStaticModuleState()); USES_CONVERSION; - CSingleLock sfLock(&ShapefileLock, TRUE); - // ---------------------------------------------- // Validation // ---------------------------------------------- @@ -3545,9 +3436,6 @@ STDMETHODIMP CShapefile::Merge(VARIANT_BOOL SelectedOnlyThis, IShapefile* sf, VA return S_OK; } - CSingleLock sfResultLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - CSingleLock sfLock(&ShapefileLock, TRUE); - const long numShapes1 = _shapeData.size(); long numShapes2; sf->get_NumShapes(&numShapes2); @@ -3705,8 +3593,6 @@ STDMETHODIMP CShapefile::SimplifyLines(DOUBLE Tolerance, VARIANT_BOOL SelectedOn AFX_MANAGE_STATE(AfxGetStaticModuleState()); USES_CONVERSION; - CSingleLock sfLock(&ShapefileLock, TRUE); - // ---------------------------------------------- // Validation // ---------------------------------------------- @@ -3810,7 +3696,6 @@ STDMETHODIMP CShapefile::SimplifyLines(DOUBLE Tolerance, VARIANT_BOOL SelectedOn STDMETHODIMP CShapefile::Segmentize(double metersTolerance, IShapefile** retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); // ---------------------------------------------- // Validating @@ -3969,7 +3854,6 @@ double CalcMinAngle(GEOSGeometry* geom, double& xCent, double& yCent) // ********************************************************************** Coloring::ColorGraph* CShapefile::GeneratePolygonColors() { - CSingleLock sfLock(&ShapefileLock, TRUE); GenerateTempQTree(false); QTree* tree = GetTempQTree(); ReadGeosGeometries(VARIANT_FALSE); @@ -4053,4 +3937,4 @@ Coloring::ColorGraph* CShapefile::GeneratePolygonColors() } #pragma endregion -// ReSharper restore CppUseAuto \ No newline at end of file +// ReSharper restore CppUseAuto diff --git a/src/COM classes/Shapefile_LabelsCharts.cpp b/src/COM classes/Shapefile_LabelsCharts.cpp index 0fdcbfc6..0875b409 100644 --- a/src/COM classes/Shapefile_LabelsCharts.cpp +++ b/src/COM classes/Shapefile_LabelsCharts.cpp @@ -35,8 +35,7 @@ // GetLabelValue // ************************************************************ void CShapefile::GetLabelString(long fieldIndex, long shapeIndex, BSTR* text, CString floatNumberFormat) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (fieldIndex != -1) +{ if (fieldIndex != -1) { CComVariant val; get_CellValue(fieldIndex, shapeIndex, &val); @@ -54,8 +53,7 @@ void CShapefile::GetLabelString(long fieldIndex, long shapeIndex, BSTR* text, CS // FieldIndex == -1: labels without text will be generated; // Method == lpNone: labels with (0.0,0.0) coordinates will be generated STDMETHODIMP CShapefile::GenerateLabels(long FieldIndex, tkLabelPositioning Method, VARIANT_BOOL LargestPartOnly, long* Count) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - *Count = 0; +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); *Count = 0; long numFields; this->get_NumFields(&numFields); @@ -181,15 +179,13 @@ STDMETHODIMP CShapefile::GenerateLabels(long FieldIndex, tkLabelPositioning Meth // ****************************************************************** // Returns reference to Labels class STDMETHODIMP CShapefile::get_Labels(ILabels** pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _labels; +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); *pVal = _labels; if (_labels) _labels->AddRef(); return S_OK; } STDMETHODIMP CShapefile::put_Labels(ILabels* newVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - if (!newVal) +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (!newVal) { ErrorMessage(tkINVALID_PARAMETER_VALUE); } @@ -205,8 +201,7 @@ STDMETHODIMP CShapefile::put_Labels(ILabels* newVal) /* put_ReferenceToLabels /***********************************************************************/ void CShapefile::put_ReferenceToLabels(bool bNullReference) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (_labels == NULL) return; +{ if (_labels == NULL) return; ((CLabels*)_labels)->put_ParentShapefile(bNullReference ? NULL : this); } #pragma endregion @@ -216,15 +211,13 @@ void CShapefile::put_ReferenceToLabels(bool bNullReference) // get/put_Charts() // ******************************************************************* STDMETHODIMP CShapefile::get_Charts (ICharts** pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _charts; +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); *pVal = _charts; if ( _charts != NULL) _charts->AddRef(); return S_OK; } STDMETHODIMP CShapefile::put_Charts (ICharts* newVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - if (!newVal) +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (!newVal) { ErrorMessage(tkINVALID_PARAMETER_VALUE); } @@ -238,8 +231,7 @@ STDMETHODIMP CShapefile::put_Charts (ICharts* newVal) /* put_ReferenceToCharts /***********************************************************************/ void CShapefile::put_ReferenceToCharts(bool bNullReference) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (!_charts) return; +{ if (!_charts) return; ((CCharts*)_charts)->put_ParentShapefile(bNullReference ? NULL: this); }; @@ -247,8 +239,7 @@ void CShapefile::put_ReferenceToCharts(bool bNullReference) // SetChartsPositions // ******************************************************************** void CShapefile::SetChartsPositions(tkLabelPositioning Method) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; +{ USES_CONVERSION; double x,y; ShpfileType shpType; @@ -365,8 +356,7 @@ void CShapefile::SetChartsPositions(tkLabelPositioning Method) // ClearChartFrames() // ************************************************************* void CShapefile::ClearChartFrames() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - for (unsigned int i = 0; i < _shapeData.size(); i++ ) +{ for (unsigned int i = 0; i < _shapeData.size(); i++ ) { CChartInfo* chart = _shapeData[i]->chart; if (chart) diff --git a/src/COM classes/Shapefile_Optimizations.cpp b/src/COM classes/Shapefile_Optimizations.cpp index 86de622e..5ebf4c88 100644 --- a/src/COM classes/Shapefile_Optimizations.cpp +++ b/src/COM classes/Shapefile_Optimizations.cpp @@ -30,8 +30,7 @@ // get_fastMode() // ************************************************************ STDMETHODIMP CShapefile::get_FastMode (VARIANT_BOOL* retval) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = _fastMode ? VARIANT_TRUE : VARIANT_FALSE; +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) *retval = _fastMode ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } @@ -39,8 +38,7 @@ STDMETHODIMP CShapefile::get_FastMode (VARIANT_BOOL* retval) // put_FastMode() // ************************************************************ STDMETHODIMP CShapefile::put_FastMode (VARIANT_BOOL newVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) if (!_isEditingShapes) { return S_OK; } @@ -62,8 +60,7 @@ STDMETHODIMP CShapefile::put_FastMode (VARIANT_BOOL newVal) // ReleaseRenderingData() // ***************************************************************** void CShapefile::ReleaseRenderingCache() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - for (unsigned int i = 0; i < _shapeData.size(); i++) { +{ for (unsigned int i = 0; i < _shapeData.size(); i++) { _shapeData[i]->ReleaseRenderingData(); } } @@ -76,8 +73,7 @@ void CShapefile::ReleaseRenderingCache() // get_NumPoints() // ***************************************************************** STDMETHODIMP CShapefile::get_NumPoints(long ShapeIndex, long *pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) *pVal = 0; if( ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) @@ -150,8 +146,7 @@ STDMETHODIMP CShapefile::get_NumPoints(long ShapeIndex, long *pVal) // ***************************************************************** //This function does not extract Z or M values!!!!!!!! STDMETHODIMP CShapefile::QuickPoint(long ShapeIndex, long PointIndex, IPoint **retval) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) if( ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) { *retval = NULL; @@ -345,9 +340,7 @@ STDMETHODIMP CShapefile::QuickPoint(long ShapeIndex, long PointIndex, IPoint **r // ***************************************************************** //This function does not extract Z or M values!!!!!!!! STDMETHODIMP CShapefile::QuickPoints(long ShapeIndex, long *NumPoints, SAFEARRAY ** retval) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - - *retval = NULL; +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) *retval = NULL; *NumPoints = 0; if( ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) @@ -541,9 +534,7 @@ STDMETHODIMP CShapefile::QuickPoints(long ShapeIndex, long *NumPoints, SAFEARRAY // ***************************************************************** //This function does not extract Z and M values STDMETHODIMP CShapefile::QuickExtents(long ShapeIndex, IExtents **retval) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - - *retval = NULL; +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) *retval = NULL; Extent ext; if (this->QuickExtentsCore(ShapeIndex, ext)) @@ -561,8 +552,7 @@ STDMETHODIMP CShapefile::QuickExtents(long ShapeIndex, IExtents **retval) // QuickExtentsCore() // ***************************************************************** bool CShapefile::QuickExtentsCore(long ShapeIndex, double* xMin, double* yMin, double* xMax, double* yMax) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - Extent ext; +{ Extent ext; if (this->QuickExtentsCore(ShapeIndex, ext)) { *xMin = ext.left; @@ -580,8 +570,7 @@ bool CShapefile::QuickExtentsCore(long ShapeIndex, double* xMin, double* yMin, d // ***************************************************************** //This function does not extract Z and M values bool CShapefile::QuickExtentsCore(long ShapeIndex, Extent& result) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if( ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) +{ if( ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) { ErrorMessage( tkINDEX_OUT_OF_BOUNDS ); return false; @@ -612,8 +601,7 @@ bool CShapefile::QuickExtentsCore(long ShapeIndex, Extent& result) // ReadShapeExtents() // ***************************************************************** bool CShapefile::ReadShapeExtents(long ShapeIndex, Extent& result) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - CSingleLock lock(&_readLock, TRUE); +{ CSingleLock lock(&_readLock, TRUE); //Get the Info from the disk fseek(_shpfile, _shpOffsets[ShapeIndex], SEEK_SET); diff --git a/src/COM classes/Shapefile_ReadWrite.cpp b/src/COM classes/Shapefile_ReadWrite.cpp index 6e6e210c..8803395b 100644 --- a/src/COM classes/Shapefile_ReadWrite.cpp +++ b/src/COM classes/Shapefile_ReadWrite.cpp @@ -34,7 +34,6 @@ STDMETHODIMP CShapefile::get_Shape(long ShapeIndex, IShape **pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); VARIANT_BOOL vbretval = VARIANT_FALSE; // out of bounds? @@ -70,8 +69,7 @@ STDMETHODIMP CShapefile::get_Shape(long ShapeIndex, IShape **pVal) // ReadFastModeShape() // ************************************************************ IShape* CShapefile::ReadFastModeShape(long ShapeIndex) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - fseek(_shpfile, _shpOffsets[ShapeIndex], SEEK_SET); +{ fseek(_shpfile, _shpOffsets[ShapeIndex], SEEK_SET); // read the shp from disk int index = ShapeUtility::ReadIntBigEndian(_shpfile); @@ -114,8 +112,7 @@ IShape* CShapefile::ReadFastModeShape(long ShapeIndex) // ReadComShape() // ************************************************************ IShape* CShapefile::ReadComShape(long ShapeIndex) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - // read the shp from disk +{ // read the shp from disk fseek(_shpfile, _shpOffsets[ShapeIndex], SEEK_SET); int intbuf; @@ -957,8 +954,7 @@ IShape* CShapefile::ReadComShape(long ShapeIndex) // ReadShx() // ************************************************************** BOOL CShapefile::ReadShx() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - // guaranteed that .shx file is open +{ // guaranteed that .shx file is open rewind(_shxfile); _shpOffsets.clear(); @@ -1025,8 +1021,7 @@ BOOL CShapefile::ReadShx() // AppendToShx() // ************************************************************** bool CShapefile::AppendToShx(FILE* shx, IShape* shp, int offset) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (!shx || !shp) return false; +{ if (!shx || !shp) return false; _shpOffsets.push_back(offset); @@ -1046,8 +1041,7 @@ bool CShapefile::AppendToShx(FILE* shx, IShape* shp, int offset) // WriteShx() // ************************************************************** BOOL CShapefile::WriteShx(FILE * shx, ICallback * cBack) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - ICallback* callback = cBack ? cBack : _globalCallback; +{ ICallback* callback = cBack ? cBack : _globalCallback; // guaranteed that .shx file is open rewind(shx); @@ -1123,8 +1117,7 @@ BOOL CShapefile::WriteShx(FILE * shx, ICallback * cBack) // GetWriteFileLength() // ************************************************************** int CShapefile::GetWriteFileLength() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - IShape * sh = NULL; +{ IShape * sh = NULL; long numPoints = 0; long numParts = 0; long part = 0; @@ -1152,8 +1145,7 @@ int CShapefile::GetWriteFileLength() // AppendToShpFile() // ************************************************************** bool CShapefile::AppendToShpFile(FILE* shp, IShapeWrapper* wrapper) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (!shp || !wrapper) return false; +{ if (!shp || !wrapper) return false; int length = wrapper->get_ContentLength(); @@ -1182,8 +1174,7 @@ bool CShapefile::AppendToShpFile(FILE* shp, IShapeWrapper* wrapper) // WriteShp() // ************************************************************** void CShapefile::WriteBounds(FILE * shp) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - double ShapefileBounds[8]; +{ double ShapefileBounds[8]; ShapefileBounds[0] = _minX; ShapefileBounds[1] = _minY; ShapefileBounds[2] = _maxX; @@ -1199,8 +1190,7 @@ void CShapefile::WriteBounds(FILE * shp) // WriteShp() // ************************************************************** BOOL CShapefile::WriteShp(FILE * shp, ICallback * cBack) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - // guaranteed that .shp file is open +{ // guaranteed that .shp file is open rewind(shp); //FILE_CODE diff --git a/src/COM classes/Shapefile_Selection.cpp b/src/COM classes/Shapefile_Selection.cpp index db8db613..5bb6160a 100644 --- a/src/COM classes/Shapefile_Selection.cpp +++ b/src/COM classes/Shapefile_Selection.cpp @@ -36,8 +36,7 @@ // ****************************************************************** CMutex selectShapesMutex(FALSE); STDMETHODIMP CShapefile::SelectShapes(IExtents *BoundBox, double Tolerance, SelectMode SelectMode, VARIANT *Result, VARIANT_BOOL *retval) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - *retval = VARIANT_FALSE; +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) *retval = VARIANT_FALSE; selectShapesMutex.Lock(); @@ -59,8 +58,7 @@ STDMETHODIMP CShapefile::SelectShapes(IExtents *BoundBox, double Tolerance, Sele // SelectShapesCore() // **************************************************************** bool CShapefile::SelectShapesCore(Extent& extents, double Tolerance, SelectMode SelectMode, std::vector& selectResult, bool renderedOnly) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - double b_minX = extents.left; +{ double b_minX = extents.left; double b_maxX = extents.right; double b_minY = extents.bottom; double b_maxY = extents.top; @@ -336,8 +334,7 @@ bool CShapefile::SelectShapesCore(Extent& extents, double Tolerance, SelectMode /***********************************************************************/ // Returns and sets the selection state for a shape. STDMETHODIMP CShapefile::get_ShapeSelected(long ShapeIndex, VARIANT_BOOL* pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - if( ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); if( ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) { *pVal = VARIANT_FALSE; ErrorMessage(tkINDEX_OUT_OF_BOUNDS); @@ -349,8 +346,7 @@ STDMETHODIMP CShapefile::get_ShapeSelected(long ShapeIndex, VARIANT_BOOL* pVal) return S_OK; } STDMETHODIMP CShapefile::put_ShapeSelected(long ShapeIndex, VARIANT_BOOL newVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - if( ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); if( ShapeIndex < 0 || ShapeIndex >= (long)_shapeData.size()) { ErrorMessage(tkINDEX_OUT_OF_BOUNDS); } @@ -365,8 +361,7 @@ STDMETHODIMP CShapefile::put_ShapeSelected(long ShapeIndex, VARIANT_BOOL newVal) // get_NumSelected // ************************************************************* STDMETHODIMP CShapefile::get_NumSelected(long *pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); long count = 0; for(int i =0; i < (int)_shapeData.size(); i++) { @@ -381,8 +376,7 @@ STDMETHODIMP CShapefile::get_NumSelected(long *pVal) // SelectAll() // ************************************************************* STDMETHODIMP CShapefile::SelectAll() -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); for (int i = 0; i < (int)_shapeData.size(); i++) { _shapeData[i]->selected(true); } @@ -394,8 +388,7 @@ STDMETHODIMP CShapefile::SelectAll() // SelectNone() // ************************************************************* STDMETHODIMP CShapefile::SelectNone() -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); for (int i = 0; i < (int)_shapeData.size(); i++) { _shapeData[i]->selected(false); } @@ -407,8 +400,7 @@ STDMETHODIMP CShapefile::SelectNone() // InvertSelection() // ************************************************************* STDMETHODIMP CShapefile::InvertSelection() -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - +{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); for (int i = 0; i < (int)_shapeData.size(); i++) { _shapeData[i]->selected(!_shapeData[i]->selected()); } diff --git a/src/COM classes/Shapefile_SpatialIndex.cpp b/src/COM classes/Shapefile_SpatialIndex.cpp index fcb48602..00d0b0d3 100644 --- a/src/COM classes/Shapefile_SpatialIndex.cpp +++ b/src/COM classes/Shapefile_SpatialIndex.cpp @@ -1,426 +1,434 @@ -//******************************************************************************************************** -//File name: Shapefile.cpp -//Description: Implementation of the CShapefile (see other cpp files as well) -//******************************************************************************************************** -//The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -//you may not use this file except in compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -//ANY KIND, either express or implied. See the License for the specific language governing rights and -//limitations under the License. -// -//The Original Code is MapWindow Open Source. -// -//The Initial Developer of this version of the Original Code is Daniel P. Ames using portions created by -//Utah State University and the Idaho National Engineering and Environmental Lab that were released as -//public domain in March 2004. -// -//Contributor(s): (Open source contributors should list themselves and their modifications here). -// ------------------------------------------------------------------------------------------------------- -// lsu 3-02-2011: split the initial Shapefile.cpp file to make entities of the reasonable size - -#include "stdafx.h" -#include "Shapefile.h" - -#pragma region SpatialIndex -// ***************************************************************** -// get_HasSpatialIndex() -// ***************************************************************** -//ajp June 2008 Property does spatial index exist -STDMETHODIMP CShapefile::get_HasSpatialIndex(VARIANT_BOOL *pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - - try - { - _hasSpatialIndex = FALSE; - CString mwdfileName = _shpfileName.Left(_shpfileName.GetLength() - 3) + "mwd"; - CString mwxfileName = _shpfileName.Left(_shpfileName.GetLength() - 3) + "mwx"; - if (Utility::FileExists(mwdfileName) && Utility::FileExists(mwxfileName)) - { - _hasSpatialIndex = TRUE; - } - } - catch (...) - { - _hasSpatialIndex = FALSE; - } - - *pVal = _hasSpatialIndex?VARIANT_TRUE:VARIANT_FALSE; - - return S_OK; -} - -// ***************************************************************** -// get_HasSpatialIndex() -// ***************************************************************** -//ajp June 2008 Property does spatial index exist -STDMETHODIMP CShapefile::put_HasSpatialIndex(VARIANT_BOOL pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - _hasSpatialIndex = pVal; // CreateSpatialIndex should be used to create it - return S_OK; -} - -bool TestIndexSearching() -{ - __try - { - IndexSearching::isValidSpatialIndex("", 0); - return true; - } - __except(1) - { - return false; - } -} - -// ***************************************************************** -// get/put_UseSpatialIndex() -// ***************************************************************** -//ajp June 2008 Property use spatial indexing -STDMETHODIMP CShapefile::get_UseSpatialIndex(VARIANT_BOOL *pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - if (_useSpatialIndex) - { - //useSpatialIndex = TestIndexSearching(); - } - *pVal = _useSpatialIndex?VARIANT_TRUE:VARIANT_FALSE; - return S_OK; -} -STDMETHODIMP CShapefile::put_UseSpatialIndex(VARIANT_BOOL pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - _useSpatialIndex = pVal; - - // Unload spatial index in case it needs to be recreated - if (!_useSpatialIndex && _spatialIndexLoaded) - { - IndexSearching::unloadSpatialIndex(_spatialIndexID); - } - return S_OK; -} - -// ***************************************************************** -// get/put_SpatialIndexMaxAreaPercent() -// ***************************************************************** -//08-24-2009 (sm) spatial index performance -STDMETHODIMP CShapefile::put_SpatialIndexMaxAreaPercent(DOUBLE newVal) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - _spatialIndexMaxAreaPercent = newVal; - return S_OK; -} -STDMETHODIMP CShapefile::get_SpatialIndexMaxAreaPercent(DOUBLE* pVal) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = _spatialIndexMaxAreaPercent; - return S_OK; -} - -// ***************************************************************** -// get_CanUseSpatialIndex() -// ***************************************************************** -//Check that the spatial index exists, is set to be used and should be used. -STDMETHODIMP CShapefile::get_CanUseSpatialIndex(IExtents* pArea, VARIANT_BOOL* pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = VARIANT_FALSE; - - double xm, xM, ym, yM, zm, zM; - pArea->GetBounds(&xm, &ym, &zm, &xM, &yM, &zM); - Extent extents(xm, xM, ym, yM); - - if (!_isEditingShapes && _useSpatialIndex) - { - VARIANT_BOOL spatialIndexExists; - get_HasSpatialIndex(&spatialIndexExists); - - if (spatialIndexExists) - { - double xM = min(_maxX, extents.right); - double xm = max(_minX, extents.left); - double yM = min(_maxY, extents.top); - double ym = max(_minY, extents.bottom); - - double shapeFileArea = (_maxX - _minX)*(_maxY - _minY); - double selectShapeArea = (xM - xm) * (yM - ym); - - if (selectShapeArea / shapeFileArea < _spatialIndexMaxAreaPercent) - { - //when large portions of the map are being drawn, - //the spatial index *probably* won't help, don't use it. - if (_spatialIndexLoaded) - { - *pVal = VARIANT_TRUE; - return S_OK; - } - else - { - USES_CONVERSION; - string baseName = W2A(_shpfileName.Left(_shpfileName.GetLength() - 4)); // TODO: use Unicode - if (IndexSearching::loadSpatialIndex(baseName, false, _spatialIndexNodeCapacity, _spatialIndexID)) - { - _spatialIndexLoaded = true; - *pVal = VARIANT_TRUE; - return S_OK; - } - } - } - } - } - return S_OK; -} - -// *********************************************************** -// CreateSpatialIndex() -// *********************************************************** -//ajp June 2008 Function to create an Index file -STDMETHODIMP CShapefile::CreateSpatialIndex(BSTR ShapefileName, VARIANT_BOOL *retval) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSingleLock sfLock(&ShapefileLock, TRUE); - USES_CONVERSION; - - *retval = VARIANT_TRUE; - - CString tmp_shpfileName = OLE2CA(ShapefileName); - if( tmp_shpfileName.GetLength() <= 3 ) - { - *retval = VARIANT_FALSE; - ErrorMessage(tkINVALID_FILENAME); - } - else - { - string baseName; - baseName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 4); - - // 0.9 = utilization rate, 100 = Node Capacity - // Creates two files baseName.dat and baseName.idx - try - { - if (!IndexSearching::createSpatialIndex(0.9, _spatialIndexNodeCapacity, (char *)baseName.c_str())) - { - *retval = VARIANT_FALSE; - ErrorMessage(tkINVALID_FILENAME); - } - } - catch (...) - { - *retval = VARIANT_FALSE; - } - } - - return S_OK; -} - -// *********************************************************** -// IsSpatialIndexValid() -// *********************************************************** -STDMETHODIMP CShapefile::IsSpatialIndexValid(VARIANT_BOOL *retval) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - VARIANT_BOOL hasSpatialIndex; - get_HasSpatialIndex(&hasSpatialIndex); - if (!hasSpatialIndex) - *retval = VARIANT_FALSE; - else - { - USES_CONVERSION; - string baseName = W2A(_shpfileName.Left(_shpfileName.GetLength() - 4)); // TODO: use Unicode - bool bIsValid = IndexSearching::isValidSpatialIndex(baseName.c_str(), _spatialIndexNodeCapacity); - *retval = bIsValid ? VARIANT_TRUE : VARIANT_FALSE; - } - - return S_OK; -} -#pragma endregion - - -#pragma region QuadTree -// ******************************************************************** -// QuickQueryInEditMode() -// ******************************************************************** -//Neio 2009/07/21 -STDMETHODIMP CShapefile::QuickQueryInEditMode(IExtents *BoundBox, int ** Result, int* ResultCount ) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - - if(! _isEditingShapes ) - { - ErrorMessage( tkSHPFILE_NOT_IN_EDIT_MODE ); - return S_OK; - } - else if( _useQTree ) - { - double xMin, yMin, zMin, xMax, yMax, zMax; - BoundBox->GetBounds(&xMin,&yMin,&zMin,&xMax,&yMax,&zMax); - - vector r = _qtree->GetNodes(QTreeExtent(xMin,xMax,yMax,yMin)); - int size = r.size(); - *Result = new int[size]; - - memcpy( *Result, &r[0], sizeof(int) * size); - *ResultCount = size; - } - return S_OK; -} - -// ***************************************************************** -// get_UseQTree() -// ***************************************************************** -STDMETHODIMP CShapefile::get_UseQTree(VARIANT_BOOL *pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - *pVal = (_useQTree)?VARIANT_TRUE:VARIANT_FALSE; - return S_OK; -} - -// ***************************************************************** -// put_UseQTree() -// ***************************************************************** -STDMETHODIMP CShapefile::put_UseQTree(VARIANT_BOOL pVal) -{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CSingleLock sfLock(&ShapefileLock, TRUE); - if (pVal) - { - if (_qtree == NULL) - this->GenerateQTree(); - _useQTree = TRUE; - } - else - { - _useQTree = FALSE; - delete _qtree; - _qtree = NULL; - } - return S_OK; -} - -// ********************************************************** -// ClearQTree -// ********************************************************** -void CShapefile::ClearQTree(double* xMin, double* xMax, double* yMin, double* yMax, double* zMin, double* zMax) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (_qtree) - { - delete _qtree; - _qtree = NULL; - } - - _qtree = this->GenerateEmptyQTree(xMin, yMin, zMin, xMax, yMax, zMax); -} - -// ********************************************************** -// GenerateEmptyQTree -// ********************************************************** -QTree* CShapefile::GenerateEmptyQTree(double* xMin, double* xMax, double* yMin, double* yMax, double* zMin, double* zMax) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - IExtents* ext = NULL; - this->get_Extents(&ext); - if (!ext) return NULL; - ext->GetBounds(xMin, yMin, zMin, xMax, yMax, zMax); - ext->Release(); - - QTree* qtree = new QTree(QTreeExtent(*xMin, *xMax, *yMax, *yMin)); - - return qtree; -} - -// ********************************************************** -// GenerateQTree -// ********************************************************** -void CShapefile::GenerateQTree() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if(_qtree) - { - delete _qtree; - _qtree = NULL; - } - - _qtree = GenerateQTreeCore(false); -} - - - -// ********************************************************************** -// GenerateQTreeCore() -// ********************************************************************** -QTree* CShapefile::GenerateQTreeCore(bool SelectedOnly) -{ - CSingleLock sfLock(&ShapefileLock, TRUE); - double xMin, xMax, yMin, yMax, zMin, zMax; - QTree* qtree = this->GenerateEmptyQTree(&xMin, &xMax, &yMin, &yMax, &zMin, &zMax); - - if (_shapeData.size() == 0) - return qtree; - - long percent; - int numShapes = (int)_shapeData.size(); - for(int i = 0; i < numShapes; i++ ) - { - if (!ShapeAvailable(i, SelectedOnly)) - continue; - - this->QuickExtentsCore(i, &xMin,&yMin,&xMax,&yMax); - - QTreeNode node; - node.Extent.left =xMin; - node.Extent.right = xMax; - node.Extent.top = yMax; - node.Extent.bottom = yMin; - node.index = i; - qtree->AddNode(node); - - CallbackHelper::Progress(_globalCallback, i, numShapes, "Building index...", _key, percent); - } - CallbackHelper::ProgressCompleted(_globalCallback, _key); - - return qtree; -} -#pragma endregion - -// Build the tree anew for geoprocessing operations, as the original one -// probably not 100% accurate/optimal + we may need only selected shapes - -// ********************************************************************** -// GenerateTempQTree() -// ********************************************************************** -bool CShapefile::GenerateTempQTree(bool SelectedOnly) -{ CSingleLock sfLock(&ShapefileLock, TRUE); - ClearTempQTree(); - _tempTree = GenerateQTreeCore(SelectedOnly); - return _tempTree != NULL; -} - -// ********************************************************************** -// ClearTempQTree() -// ********************************************************************** -void CShapefile::ClearTempQTree() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - if (_tempTree) - { - delete _tempTree; - _tempTree = NULL; - } -} - -// ********************************************************************** -// GetTempQtree() -// ********************************************************************** -QTree* CShapefile::GetTempQTree() -{ CSingleLock sfLock(&ShapefileLock, TRUE); - return _tempTree; -} - -// ********************************************************************** -// RemoveSpatialIndex() -// ********************************************************************** -STDMETHODIMP CShapefile::RemoveSpatialIndex(VARIANT_BOOL* retVal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); - *retVal = VARIANT_TRUE; - CStringW names[] = {L"mwd", L"mwx"}; - - for (int i = 0; i < 2; i++) - { - CString name = _shpfileName.Left(_shpfileName.GetLength() - 3) + names[i]; - if (Utility::FileExists(name)) - { - if (remove(name) != 0) { - ErrorMessage(tkCANT_DELETE_FILE); - *retVal = VARIANT_FALSE; - } - } - } - return S_OK; +//******************************************************************************************************** +//File name: Shapefile.cpp +//Description: Implementation of the CShapefile (see other cpp files as well) +//******************************************************************************************************** +//The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); +//you may not use this file except in compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +//ANY KIND, either express or implied. See the License for the specific language governing rights and +//limitations under the License. +// +//The Original Code is MapWindow Open Source. +// +//The Initial Developer of this version of the Original Code is Daniel P. Ames using portions created by +//Utah State University and the Idaho National Engineering and Environmental Lab that were released as +//public domain in March 2004. +// +//Contributor(s): (Open source contributors should list themselves and their modifications here). +// ------------------------------------------------------------------------------------------------------- +// lsu 3-02-2011: split the initial Shapefile.cpp file to make entities of the reasonable size + +#include "stdafx.h" +#include "Shapefile.h" + +#pragma region SpatialIndex +// ***************************************************************** +// get_HasSpatialIndex() +// ***************************************************************** +//ajp June 2008 Property does spatial index exist +STDMETHODIMP CShapefile::get_HasSpatialIndex(VARIANT_BOOL *pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + + try + { + _hasSpatialIndex = FALSE; + CString mwdfileName = _shpfileName.Left(_shpfileName.GetLength() - 3) + "mwd"; + CString mwxfileName = _shpfileName.Left(_shpfileName.GetLength() - 3) + "mwx"; + if (Utility::FileExists(mwdfileName) && Utility::FileExists(mwxfileName)) + { + _hasSpatialIndex = TRUE; + } + } + catch (...) + { + _hasSpatialIndex = FALSE; + } + + *pVal = _hasSpatialIndex?VARIANT_TRUE:VARIANT_FALSE; + + return S_OK; +} + +// ***************************************************************** +// get_HasSpatialIndex() +// ***************************************************************** +//ajp June 2008 Property does spatial index exist +STDMETHODIMP CShapefile::put_HasSpatialIndex(VARIANT_BOOL pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + _hasSpatialIndex = pVal; // CreateSpatialIndex should be used to create it + return S_OK; +} + +bool TestIndexSearching() +{ + __try + { + IndexSearching::isValidSpatialIndex("", 0); + return true; + } + __except(1) + { + return false; + } +} + +// ***************************************************************** +// get/put_UseSpatialIndex() +// ***************************************************************** +//ajp June 2008 Property use spatial indexing +STDMETHODIMP CShapefile::get_UseSpatialIndex(VARIANT_BOOL *pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + if (_useSpatialIndex) + { + //useSpatialIndex = TestIndexSearching(); + } + *pVal = _useSpatialIndex?VARIANT_TRUE:VARIANT_FALSE; + return S_OK; +} +STDMETHODIMP CShapefile::put_UseSpatialIndex(VARIANT_BOOL pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + _useSpatialIndex = pVal; + + // Unload spatial index in case it needs to be recreated + if (!_useSpatialIndex && _spatialIndexLoaded) + { + IndexSearching::unloadSpatialIndex(_spatialIndexID); + } + return S_OK; +} + +// ***************************************************************** +// get/put_SpatialIndexMaxAreaPercent() +// ***************************************************************** +//08-24-2009 (sm) spatial index performance +STDMETHODIMP CShapefile::put_SpatialIndexMaxAreaPercent(DOUBLE newVal) +{ + _spatialIndexMaxAreaPercent = newVal; + return S_OK; +} +STDMETHODIMP CShapefile::get_SpatialIndexMaxAreaPercent(DOUBLE* pVal) +{ + *pVal = _spatialIndexMaxAreaPercent; + return S_OK; +} + +// ***************************************************************** +// get_CanUseSpatialIndex() +// ***************************************************************** +//Check that the spatial index exists, is set to be used and should be used. +STDMETHODIMP CShapefile::get_CanUseSpatialIndex(IExtents* pArea, VARIANT_BOOL* pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + *pVal = VARIANT_FALSE; + + double xm, xM, ym, yM, zm, zM; + pArea->GetBounds(&xm, &ym, &zm, &xM, &yM, &zM); + Extent extents(xm, xM, ym, yM); + + if (!_isEditingShapes && _useSpatialIndex) + { + VARIANT_BOOL spatialIndexExists; + get_HasSpatialIndex(&spatialIndexExists); + + if (spatialIndexExists) + { + double xM = min(_maxX, extents.right); + double xm = max(_minX, extents.left); + double yM = min(_maxY, extents.top); + double ym = max(_minY, extents.bottom); + + double shapeFileArea = (_maxX - _minX)*(_maxY - _minY); + double selectShapeArea = (xM - xm) * (yM - ym); + + if (selectShapeArea / shapeFileArea < _spatialIndexMaxAreaPercent) + { + //when large portions of the map are being drawn, + //the spatial index *probably* won't help, don't use it. + if (_spatialIndexLoaded) + { + *pVal = VARIANT_TRUE; + return S_OK; + } + else + { + USES_CONVERSION; + string baseName = W2A(_shpfileName.Left(_shpfileName.GetLength() - 4)); // TODO: use Unicode + if (IndexSearching::loadSpatialIndex(baseName, false, _spatialIndexNodeCapacity, _spatialIndexID)) + { + _spatialIndexLoaded = true; + *pVal = VARIANT_TRUE; + return S_OK; + } + } + } + } + } + return S_OK; +} + +// *********************************************************** +// CreateSpatialIndex() +// *********************************************************** +//ajp June 2008 Function to create an Index file +STDMETHODIMP CShapefile::CreateSpatialIndex(BSTR ShapefileName, VARIANT_BOOL *retval) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()) + USES_CONVERSION; + + *retval = VARIANT_TRUE; + + CString tmp_shpfileName = OLE2CA(ShapefileName); + if( tmp_shpfileName.GetLength() <= 3 ) + { + *retval = VARIANT_FALSE; + ErrorMessage(tkINVALID_FILENAME); + } + else + { + string baseName; + baseName = tmp_shpfileName.Left(tmp_shpfileName.GetLength() - 4); + + // 0.9 = utilization rate, 100 = Node Capacity + // Creates two files baseName.dat and baseName.idx + try + { + if (!IndexSearching::createSpatialIndex(0.9, _spatialIndexNodeCapacity, (char *)baseName.c_str())) + { + *retval = VARIANT_FALSE; + ErrorMessage(tkINVALID_FILENAME); + } + } + catch (...) + { + *retval = VARIANT_FALSE; + } + } + + return S_OK; +} + +// *********************************************************** +// IsSpatialIndexValid() +// *********************************************************** +STDMETHODIMP CShapefile::IsSpatialIndexValid(VARIANT_BOOL *retval) +{ + VARIANT_BOOL hasSpatialIndex; + get_HasSpatialIndex(&hasSpatialIndex); + if (!hasSpatialIndex) + *retval = VARIANT_FALSE; + else + { + USES_CONVERSION; + string baseName = W2A(_shpfileName.Left(_shpfileName.GetLength() - 4)); // TODO: use Unicode + bool bIsValid = IndexSearching::isValidSpatialIndex(baseName.c_str(), _spatialIndexNodeCapacity); + *retval = bIsValid ? VARIANT_TRUE : VARIANT_FALSE; + } + + return S_OK; +} +#pragma endregion + + +#pragma region QuadTree +// ******************************************************************** +// QuickQueryInEditMode() +// ******************************************************************** +//Neio 2009/07/21 +STDMETHODIMP CShapefile::QuickQueryInEditMode(IExtents *BoundBox, int ** Result, int* ResultCount ) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + if(! _isEditingShapes ) + { + ErrorMessage( tkSHPFILE_NOT_IN_EDIT_MODE ); + return S_OK; + } + else if( _useQTree ) + { + double xMin, yMin, zMin, xMax, yMax, zMax; + BoundBox->GetBounds(&xMin,&yMin,&zMin,&xMax,&yMax,&zMax); + + vector r = _qtree->GetNodes(QTreeExtent(xMin,xMax,yMax,yMin)); + int size = r.size(); + *Result = new int[size]; + + memcpy( *Result, &r[0], sizeof(int) * size); + *ResultCount = size; + } + return S_OK; +} + +// ***************************************************************** +// get_UseQTree() +// ***************************************************************** +STDMETHODIMP CShapefile::get_UseQTree(VARIANT_BOOL *pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *pVal = (_useQTree)?VARIANT_TRUE:VARIANT_FALSE; + return S_OK; +} + +// ***************************************************************** +// put_UseQTree() +// ***************************************************************** +STDMETHODIMP CShapefile::put_UseQTree(VARIANT_BOOL pVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if (pVal) + { + if (_qtree == NULL) + this->GenerateQTree(); + _useQTree = TRUE; + } + else + { + _useQTree = FALSE; + delete _qtree; + _qtree = NULL; + } + return S_OK; +} + +// ********************************************************** +// ClearQTree +// ********************************************************** +void CShapefile::ClearQTree(double* xMin, double* xMax, double* yMin, double* yMax, double* zMin, double* zMax) +{ + if (_qtree) + { + delete _qtree; + _qtree = NULL; + } + + _qtree = this->GenerateEmptyQTree(xMin, yMin, zMin, xMax, yMax, zMax); +} + +// ********************************************************** +// GenerateEmptyQTree +// ********************************************************** +QTree* CShapefile::GenerateEmptyQTree(double* xMin, double* xMax, double* yMin, double* yMax, double* zMin, double* zMax) +{ + IExtents* ext = NULL; + this->get_Extents(&ext); + if (!ext) return NULL; + ext->GetBounds(xMin, yMin, zMin, xMax, yMax, zMax); + ext->Release(); + + QTree* qtree = new QTree(QTreeExtent(*xMin, *xMax, *yMax, *yMin)); + + return qtree; +} + +// ********************************************************** +// GenerateQTree +// ********************************************************** +void CShapefile::GenerateQTree() +{ + if(_qtree) + { + delete _qtree; + _qtree = NULL; + } + + _qtree = GenerateQTreeCore(false); +} + + + +// ********************************************************************** +// GenerateQTreeCore() +// ********************************************************************** +QTree* CShapefile::GenerateQTreeCore(bool SelectedOnly) +{ + + double xMin, xMax, yMin, yMax, zMin, zMax; + QTree* qtree = this->GenerateEmptyQTree(&xMin, &xMax, &yMin, &yMax, &zMin, &zMax); + + if (_shapeData.size() == 0) + return qtree; + + long percent; + int numShapes = (int)_shapeData.size(); + for(int i = 0; i < numShapes; i++ ) + { + if (!ShapeAvailable(i, SelectedOnly)) + continue; + + this->QuickExtentsCore(i, &xMin,&yMin,&xMax,&yMax); + + QTreeNode node; + node.Extent.left =xMin; + node.Extent.right = xMax; + node.Extent.top = yMax; + node.Extent.bottom = yMin; + node.index = i; + qtree->AddNode(node); + + CallbackHelper::Progress(_globalCallback, i, numShapes, "Building index...", _key, percent); + } + CallbackHelper::ProgressCompleted(_globalCallback, _key); + + return qtree; +} +#pragma endregion + +// Build the tree anew for geoprocessing operations, as the original one +// probably not 100% accurate/optimal + we may need only selected shapes + +// ********************************************************************** +// GenerateTempQTree() +// ********************************************************************** +bool CShapefile::GenerateTempQTree(bool SelectedOnly) +{ + ClearTempQTree(); + _tempTree = GenerateQTreeCore(SelectedOnly); + return _tempTree != NULL; +} + +// ********************************************************************** +// ClearTempQTree() +// ********************************************************************** +void CShapefile::ClearTempQTree() +{ + if (_tempTree) + { + delete _tempTree; + _tempTree = NULL; + } +} + +// ********************************************************************** +// GetTempQtree() +// ********************************************************************** +QTree* CShapefile::GetTempQTree() +{ + return _tempTree; +} + +// ********************************************************************** +// RemoveSpatialIndex() +// ********************************************************************** +STDMETHODIMP CShapefile::RemoveSpatialIndex(VARIANT_BOOL* retVal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + *retVal = VARIANT_TRUE; + CStringW names[] = {L"mwd", L"mwx"}; + + for (int i = 0; i < 2; i++) + { + CString name = _shpfileName.Left(_shpfileName.GetLength() - 3) + names[i]; + if (Utility::FileExists(name)) + { + if (remove(name) != 0) { + ErrorMessage(tkCANT_DELETE_FILE); + *retVal = VARIANT_FALSE; + } + } + } + return S_OK; } \ No newline at end of file diff --git a/src/COM classes/Shapefile_Validation.cpp b/src/COM classes/Shapefile_Validation.cpp index 0544faf1..44bd84fe 100644 --- a/src/COM classes/Shapefile_Validation.cpp +++ b/src/COM classes/Shapefile_Validation.cpp @@ -37,7 +37,6 @@ STDMETHODIMP CShapefile::Validate(tkShapeValidationMode validationMode, VARIANT_ IShapeValidationInfo** results) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); *results = nullptr; if (validationMode == NoValidation) @@ -63,7 +62,6 @@ STDMETHODIMP CShapefile::Validate(tkShapeValidationMode validationMode, VARIANT_ bool CShapefile::ValidateInput(IShapefile* isf, CString methodName, CString parameterName, VARIANT_BOOL selectedOnly, CString className /*= "Shapefile"*/) { - CSingleLock mySfLock(&ShapefileLock, TRUE); // MWGIS-132; this code, suggested by CLang for MWGIS-104 on 24 Aug 2018, // is being removed because it prevents any in-memory Shapefile from passing // validation (since in-memory shapefiles have no FILE * (_shpfile == NULL). @@ -99,10 +97,6 @@ IShapeValidationInfo* CShapefile::ValidateInputCore(IShapefile* isf, CString met tkShapeValidationMode validationMode, CString className, bool reportOnly) { - if (!isf) return nullptr; - - CSingleLock sfLock(&((CShapefile*)isf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); tkShapefileSourceType sourceType; if (isf->get_SourceType(&sourceType)) { @@ -150,9 +144,6 @@ IShapeValidationInfo* CShapefile::ValidateOutput(IShapefile** isf, CString metho { if (!*isf) return nullptr; - CSingleLock sfLock(&((CShapefile*)*isf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); - long numShapes; (*isf)->get_NumShapes(&numShapes); if (numShapes == 0 && abortIfEmpty) @@ -196,9 +187,6 @@ IShapeValidationInfo* CShapefile::ValidateOutput(IShapefile** isf, CString metho // ************************************************************** bool CShapefile::ValidateOutput(IShapefile* sf, CString methodName, CString className, bool abortIfEmpty) { - if (!sf) return false; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - CSingleLock mySfLock(&ShapefileLock, TRUE); if (!_isEditingShapes) { return true; @@ -213,7 +201,6 @@ bool CShapefile::ValidateOutput(IShapefile* sf, CString methodName, CString clas // ********************************************************* HRESULT CShapefile::GetValidatedShape(int shapeIndex, IShape** retVal) { - CSingleLock sfLock(&ShapefileLock, TRUE); IShape* shp = nullptr; get_Shape(shapeIndex, &shp); @@ -275,7 +262,6 @@ HRESULT CShapefile::GetValidatedShape(int shapeIndex, IShape** retVal) // ********************************************************* bool CShapefile::ShapeAvailable(int shapeIndex, VARIANT_BOOL selectedOnly) { - CSingleLock sfLock(&ShapefileLock, TRUE); if (shapeIndex < 0 || shapeIndex >= (int)_shapeData.size()) { return false; @@ -298,7 +284,6 @@ bool CShapefile::ShapeAvailable(int shapeIndex, VARIANT_BOOL selectedOnly) // ********************************************************* GEOSGeometry* CShapefile::GetGeosGeometry(int shapeIndex) { - CSingleLock sfLock(&ShapefileLock, TRUE); return _shapeData[shapeIndex]->geosGeom; } @@ -308,7 +293,6 @@ GEOSGeometry* CShapefile::GetGeosGeometry(int shapeIndex) STDMETHODIMP CShapefile::ClearCachedGeometries() { AFX_MANAGE_STATE(AfxGetStaticModuleState()) - CSingleLock sfLock(&ShapefileLock, TRUE); if (_geosGeometriesRead) { for (auto& i : _shapeData) @@ -329,7 +313,6 @@ STDMETHODIMP CShapefile::ClearCachedGeometries() // ********************************************************* void CShapefile::ReadGeosGeometries(VARIANT_BOOL selectedOnly) { - CSingleLock sfLock(&ShapefileLock, TRUE); if (_geosGeometriesRead) { CallbackHelper::AssertionFailed("Attempt to reread GEOS geometries while they are in memory."); @@ -366,4 +349,4 @@ void CShapefile::ReadGeosGeometries(VARIANT_BOOL selectedOnly) #pragma endregion -// ReSharper restore CppUseAuto \ No newline at end of file +// ReSharper restore CppUseAuto diff --git a/src/COM classes/Utils.cpp b/src/COM classes/Utils.cpp index 779fdc82..d1145e66 100644 --- a/src/COM classes/Utils.cpp +++ b/src/COM classes/Utils.cpp @@ -385,8 +385,6 @@ STDMETHODIMP CUtils::RemoveColinearPoints(IShapefile * Shapes, double LinearTole return S_OK; } - CSingleLock sfLock(&((CShapefile*) Shapes)->ShapefileLock, TRUE); - ICallback* callback = cBack ? cBack : _globalCallback; ShpfileType shptype; @@ -1163,8 +1161,6 @@ STDMETHODIMP CUtils::ShapeToShapeZ(IShapefile * Shapefile, IGrid *Grid, ICallbac return S_OK; } - CSingleLock sfLock(&((CShapefile*)Shapefile)->ShapefileLock, TRUE); - long ncols = 0, nrows = 0; IGridHeader * header = NULL; Grid->get_Header(&header); @@ -2744,8 +2740,6 @@ STDMETHODIMP CUtils::ShapefileToGrid(IShapefile * Shpfile, VARIANT_BOOL UseShape return S_OK; } - CSingleLock sfLock(&((CShapefile*)Shpfile)->ShapefileLock, TRUE); - if (!((CShapefile*)Shpfile)->ValidateInput(Shpfile, "ShapefileToGrid", "Shpfile", VARIANT_FALSE, "Utils")) return S_OK; @@ -3589,8 +3583,6 @@ STDMETHODIMP CUtils::ReprojectShapefile(IShapefile* sf, IGeoProjection* source, return S_OK; } - CSingleLock sfLock(&((CShapefile*) sf)->ShapefileLock, TRUE); - OGRSpatialReference* ref1 = ((CGeoProjection*)source)->get_SpatialReference(); OGRSpatialReference* ref2 = ((CGeoProjection*)target)->get_SpatialReference(); @@ -4129,8 +4121,6 @@ STDMETHODIMP CUtils::GridStatisticsToShapefile(IGrid* grid, IShapefile* sf, VARI return S_OK; } - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - ShpfileType type; sf->get_ShapefileType(&type); if (type != SHP_POLYGON && type != SHP_POLYGONM && type != SHP_POLYGONZ) { @@ -6054,4 +6044,4 @@ STDMETHODIMP CUtils::LineProjectDistanceTo(IShape* sourceLine, IShape* reference return S_OK; } -// ReSharper restore CppUseAuto \ No newline at end of file +// ReSharper restore CppUseAuto diff --git a/src/COM classes/Utils_Shapefile.cpp b/src/COM classes/Utils_Shapefile.cpp index 4e8b09ed..09a66263 100644 --- a/src/COM classes/Utils_Shapefile.cpp +++ b/src/COM classes/Utils_Shapefile.cpp @@ -8,8 +8,6 @@ // ******************************************************** VARIANT_BOOL CUtils::SaveOutputShapefile(BSTR outputFilename, IShapefile* sf, VARIANT_BOOL overwrite) { - if (!sf) return VARIANT_FALSE; - if (Utility::FileExistsW(outputFilename)) { if (!overwrite) { @@ -23,7 +21,6 @@ VARIANT_BOOL CUtils::SaveOutputShapefile(BSTR outputFilename, IShapefile* sf, VA } } - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); VARIANT_BOOL vb; sf->SaveAsEx(outputFilename, VARIANT_TRUE, VARIANT_FALSE, &vb); @@ -43,8 +40,6 @@ VARIANT_BOOL CUtils::SaveOutputShapefile(BSTR outputFilename, IShapefile* sf, VA // ******************************************************** void CUtils::CloseOutputShapefile(IShapefile* sf) { - if (!sf) return; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); sf->StopAppendMode(); VARIANT_BOOL vb; @@ -71,7 +66,6 @@ bool CUtils::CheckInputShapefile(IShapefile* input) IShapefile* CUtils::CloneInput(IShapefile* input, BSTR outputFilename, VARIANT_BOOL overwrite) { if (!CheckInputShapefile(input)) return S_OK; - CSingleLock sfLock(&((CShapefile*)input)->ShapefileLock, TRUE); IShapefile* result = NULL; input->Clone(&result); @@ -90,8 +84,6 @@ IShapefile* CUtils::CloneInput(IShapefile* input, BSTR outputFilename, VARIANT_B STDMETHODIMP CUtils::FixUpShapes(IShapefile* subject, VARIANT_BOOL SelectedOnly, BSTR outputFilename, VARIANT_BOOL overwrite, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - if (!CheckInputShapefile(subject)) return S_OK; - CSingleLock sfLock(&((CShapefile*)subject)->ShapefileLock, TRUE); *retVal = VARIANT_FALSE; @@ -118,7 +110,6 @@ STDMETHODIMP CUtils::BufferByDistance(IShapefile* subject, DOUBLE Distance, LONG *retVal = VARIANT_FALSE; if (!CheckInputShapefile(subject)) return S_OK; - CSingleLock sfLock(&((CShapefile*)subject)->ShapefileLock, TRUE); IShapefile* result = NULL; @@ -158,8 +149,6 @@ STDMETHODIMP CUtils::BufferByDistance(IShapefile* subject, DOUBLE Distance, LONG STDMETHODIMP CUtils::ExplodeShapes(IShapefile* subject, VARIANT_BOOL SelectedOnly, BSTR outputFilename, VARIANT_BOOL Overwrite, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - if (!CheckInputShapefile(subject)) return S_OK; - CSingleLock sfLock(&((CShapefile*)subject)->ShapefileLock, TRUE); *retVal = VARIANT_FALSE; @@ -182,9 +171,6 @@ STDMETHODIMP CUtils::ExportSelection(IShapefile* subject, BSTR outputFilename, V { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - if (!CheckInputShapefile(subject)) return S_OK; - CSingleLock sfLock(&((CShapefile*)subject)->ShapefileLock, TRUE); - *retVal = VARIANT_FALSE; IShapefile* result = CloneInput(subject, outputFilename, Overwrite); diff --git a/src/ComHelpers/CallbackHelper.h b/src/ComHelpers/CallbackHelper.h index e877bd09..a6f0ecf5 100644 --- a/src/ComHelpers/CallbackHelper.h +++ b/src/ComHelpers/CallbackHelper.h @@ -1,7 +1,4 @@ #pragma once - -#include "MapWinGIS_i.h" - namespace CallbackHelper { void Progress(ICallback* callback, int index, double count, const char* message, BSTR& key, long& lastPercent); diff --git a/src/ComHelpers/ChartsHelper.cpp b/src/ComHelpers/ChartsHelper.cpp index 2fb549d2..5cb5611c 100644 --- a/src/ComHelpers/ChartsHelper.cpp +++ b/src/ComHelpers/ChartsHelper.cpp @@ -1,5 +1,4 @@ #include "stdafx.h" -#include "Shapefile.h" #include "ChartsHelper.h" // ******************************************************************* @@ -9,7 +8,6 @@ bool ChartsHelper::ReadChartFields(IShapefile* sf, std::vector* values) { if (!sf) return false; - CSingleLock sfLock(&((CShapefile*) sf)->ShapefileLock, TRUE); struct FieldIndex { @@ -92,7 +90,6 @@ bool ChartsHelper::ReadChartFields(IShapefile* sf, std::vector* values) bool ChartsHelper::ReadChartField(IShapefile* sf, std::vector* values, int fieldIndex) { if (!sf) return false; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); IField* fld = NULL; sf->get_Field(fieldIndex, &fld); diff --git a/src/ComHelpers/FieldHelper.cpp b/src/ComHelpers/FieldHelper.cpp index 7bc243c4..16d2fd06 100644 --- a/src/ComHelpers/FieldHelper.cpp +++ b/src/ComHelpers/FieldHelper.cpp @@ -10,8 +10,6 @@ long FieldHelper::FindNewShapeID(IShapefile* sf, long FieldIndex) { if (!sf) return 0; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - CComPtr table = NULL; sf->get_Table(&table); if (!table) return 0; diff --git a/src/ComHelpers/LabelsHelper.cpp b/src/ComHelpers/LabelsHelper.cpp index ffe560dc..14715263 100644 --- a/src/ComHelpers/LabelsHelper.cpp +++ b/src/ComHelpers/LabelsHelper.cpp @@ -8,13 +8,9 @@ // Should be called after change of shapefile type (CreateNew, Open, Resource, Close) void LabelsHelper::UpdateLabelsPositioning(IShapefile* sf) { - if (!sf) return; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); ShpfileType type = ShapefileHelper::GetShapeType2D(sf); CComPtr labels = NULL; sf->get_Labels(&labels); - sfLock.Unlock(); - if (labels) { if (type == SHP_POINT || type == SHP_MULTIPOINT) diff --git a/src/Control/DispIds.h b/src/Control/DispIds.h index e5434021..19466ce6 100644 --- a/src/Control/DispIds.h +++ b/src/Control/DispIds.h @@ -3,6 +3,7 @@ enum { //{{AFX_DISP_ID(CMapView) // NOTE: ClassWizard will add and remove enumeration elements here // DO NOT EDIT what you see in these blocks of generated code ! // **ClassWizard is a thing of the past... feel free to edit this code. + dispidSetLatitudeLongitude = 267L, dispidStartNewBoundShapeEx = 266L, dispidStartNewBoundShape = 265L, dispidRestartBackgroundLoading = 264L, diff --git a/src/Control/Map.h b/src/Control/Map.h index a859c28e..3b4c12b9 100644 --- a/src/Control/Map.h +++ b/src/Control/Map.h @@ -572,6 +572,7 @@ class CMapView : public COleControl, IMapViewCallback afx_msg float GetLatitude(); afx_msg void SetLongitude(float nNewValue); afx_msg float GetLongitude(); + afx_msg void SetLatitudeLongitude(double latitude, double longitude); afx_msg void SetCurrentZoom(int nNewValue); afx_msg int GetCurrentZoom(); afx_msg void SetTileProvider(tkTileProvider nNewValue); diff --git a/src/Control/Map_DispatchMap.cpp b/src/Control/Map_DispatchMap.cpp index 616de98a..418f35f4 100644 --- a/src/Control/Map_DispatchMap.cpp +++ b/src/Control/Map_DispatchMap.cpp @@ -249,6 +249,7 @@ BEGIN_DISPATCH_MAP(CMapView, COleControl) DISP_PROPERTY_EX_ID(CMapView, "FileManager", dispidFileManager, GetFileManager, SetNotSupported, VT_DISPATCH) DISP_PROPERTY_EX_ID(CMapView, "Latitude", dispidLatitude, GetLatitude, SetLatitude, VT_R4) DISP_PROPERTY_EX_ID(CMapView, "Longitude", dispidLongitude, GetLongitude, SetLongitude, VT_R4) + DISP_FUNCTION_ID(CMapView, "SetLatitudeLongitude", dispidSetLatitudeLongitude, SetLatitudeLongitude, VT_EMPTY, VTS_R8 VTS_R8) DISP_PROPERTY_EX_ID(CMapView, "CurrentZoom", dispidCurrentZoom, GetCurrentZoom, SetCurrentZoom, VT_I4) DISP_PROPERTY_EX_ID(CMapView, "TileProvider", dispidTileProvider, GetTileProvider, SetTileProvider, VT_I2) DISP_PROPERTY_EX_ID(CMapView, "Projection", dispidMapProjection, GetProjection, SetProjection, VT_I2) diff --git a/src/Control/Map_Drawing.cpp b/src/Control/Map_Drawing.cpp index 5bdd8862..6dfd7139 100644 --- a/src/Control/Map_Drawing.cpp +++ b/src/Control/Map_Drawing.cpp @@ -901,13 +901,6 @@ void CMapView::DrawLayers(const CRect & rcBounds, Gdiplus::Graphics* graphics, b if (visible) { - // This is used for regular & dynamic ogr 'shapefile' layers - auto _DrawShapeFileCore = [&](CComPtr sf) { - sfDrawer.Draw(rcBounds, sf); - LayerDrawer::DrawLabels(l, lblDrawer, vpAboveParentLayer); - LayerDrawer::DrawCharts(l, chartDrawer, vpAboveParentLayer); - }; - if (l->IsImage()) { if (!layerBuffer) continue; @@ -916,8 +909,9 @@ void CMapView::DrawLayers(const CRect & rcBounds, Gdiplus::Graphics* graphics, b LayerDrawer::DrawLabels(l, lblDrawer, vpAboveParentLayer); } - else if (l->IsShapefile() || l->IsDynamicOgrLayer()) + else if (l->IsShapefile() || l->IsDynamicOgrLayer()) { + CComPtr sf = NULL; if (l->IsDynamicOgrLayer()) { @@ -927,21 +921,26 @@ void CMapView::DrawLayers(const CRect & rcBounds, Gdiplus::Graphics* graphics, b // Get the shapefile l->QueryShapefile(&sf); } - else - { - // grab extents from shapefile in case they changed - l->UpdateExtentsFromDatasource(); + else + { + // grab extents from shapefile in case they changed + l->UpdateExtentsFromDatasource(); - if (!l->extents.Intersects(_extents)) - continue; + if (!l->extents.Intersects(_extents)) + continue; // layerBuffer == true indicates we're drawing the non-Volatile layers if (l->QueryShapefile(&sf) && ShapefileHelper::IsVolatile(sf) == layerBuffer) continue; - } + // Update labels & categories + l->UpdateShapefile(); + } + // Perform the draw: - _DrawShapeFileCore(sf); + sfDrawer.Draw(rcBounds, sf); + LayerDrawer::DrawLabels(l, lblDrawer, vpAboveParentLayer); + LayerDrawer::DrawCharts(l, chartDrawer, vpAboveParentLayer); } } } diff --git a/src/Control/Map_Scale.cpp b/src/Control/Map_Scale.cpp index a34f55d3..c57a30cc 100644 --- a/src/Control/Map_Scale.cpp +++ b/src/Control/Map_Scale.cpp @@ -1772,7 +1772,7 @@ bool CMapView::SetGeoPosition(double x, double y) } // **************************************************************** -// Latitude() +// SetLatitude() // **************************************************************** void CMapView::SetLatitude(float latitude) { @@ -1793,7 +1793,7 @@ float CMapView::GetLatitude() } // **************************************************************** -// Longitude() +// SetLongitude() // **************************************************************** void CMapView::SetLongitude(float longitude) { @@ -1803,6 +1803,7 @@ void CMapView::SetLongitude(float longitude) } SetGeoPosition(longitude, GetLatitude()); } + float CMapView::GetLongitude() { double x, y; @@ -1811,6 +1812,21 @@ float CMapView::GetLongitude() return 0.0; } +// **************************************************************** +// SetLatitudeLongitude() +// **************************************************************** +void CMapView::SetLatitudeLongitude(double latitude, double longitude) +{ + if (abs(latitude) > 90.0 || abs(longitude) > 180.0) + { + ErrorMessage(tkINVALID_PARAMETER_VALUE); + return; + } + + SetGeoPosition(longitude, latitude); +} + + // **************************************************************** // CurrentZoom() // **************************************************************** diff --git a/src/Control/Map_Shapefile.cpp b/src/Control/Map_Shapefile.cpp index fe10e73c..16a15a03 100644 --- a/src/Control/Map_Shapefile.cpp +++ b/src/Control/Map_Shapefile.cpp @@ -1086,8 +1086,6 @@ long CMapView::GetShapePointFontCharListID(long LayerHandle, long Shape) STDMETHODIMP CShapefile::SaveAsEx(BSTR newFilename, VARIANT_BOOL stopEditing, VARIANT_BOOL unboundFile, VARIANT_BOOL* retVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - CSingleLock sfLock(&ShapefileLock, TRUE); - if (unboundFile) { Save(NULL, retVal); diff --git a/src/Control/Map_Snapshot.cpp b/src/Control/Map_Snapshot.cpp index 77cd5b3d..95a34c38 100644 --- a/src/Control/Map_Snapshot.cpp +++ b/src/Control/Map_Snapshot.cpp @@ -1,5 +1,5 @@ /************************************************************************************** - * File name: Map_Snamshot.cpp + * File name: Map_Snapshot.cpp * * Project: MapWindow Open Source (MapWinGis ActiveX control) * Description: implementation of the snapshot functions. diff --git a/src/Drawing/ChartDrawing.cpp b/src/Drawing/ChartDrawing.cpp index 422278f7..218ae9d3 100644 --- a/src/Drawing/ChartDrawing.cpp +++ b/src/Drawing/ChartDrawing.cpp @@ -61,7 +61,6 @@ bool CChartDrawer::PrepareValues(IShapefile* sf, ICharts* charts, ChartOptions* std::vector& arr, std::vector& values) { CShapefile* sfClass = (CShapefile*)sf; - CSingleLock sfLock(&(sfClass->ShapefileLock), TRUE); if (!ChartsHelper::ReadChartFields(sfClass, &values)) { return false; @@ -129,7 +128,6 @@ bool CChartDrawer::PrepareValues(IShapefile* sf, ICharts* charts, ChartOptions* bool CChartDrawer::NormalizeValues(ICharts* charts, IShapefile* sf, ChartOptions* options, vector values) { CShapefile* sfClass = (CShapefile*)sf; - CSingleLock sfLock(&(sfClass->ShapefileLock), TRUE); long numBars; charts->get_NumFields(&numBars); @@ -170,7 +168,6 @@ bool CChartDrawer::NormalizeValues(ICharts* charts, IShapefile* sf, ChartOptions void CChartDrawer::DrawCharts(IShapefile* sf) { if (!sf) return; - CSingleLock sfLock(&((CShapefile*) sf)->ShapefileLock, TRUE); REAL dx = _graphics->GetDpiX(); @@ -269,9 +266,6 @@ void CChartDrawer::DrawPieCharts(IShapefile* sf, ICharts* charts, ChartOptions* std::vector& arr, std::vector& brushes, std::vector& brushesDimmed, long numBars, Pen& pen, CString sFormat, CBrush& brushFrame, CPen& penFrame, Gdiplus::Font* gdiPlusFont) { - if (!sf) return; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - long collisionBuffer = ChartsHelper::GetCollisionBuffer(charts); REAL offsetX = static_cast(ChartsHelper::GetOffsetX(charts)); REAL offsetY = static_cast(ChartsHelper::GetOffsetY(charts)); @@ -573,9 +567,6 @@ void CChartDrawer::DrawBarCharts(IShapefile* sf, ICharts* charts, ChartOptions* long numBars, Pen& pen, CString sFormat, bool vertical, CBrush& brushFrame, CPen& penFrame, Gdiplus::Font* gdiPlusFont) { - if (!sf) return; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - long collisionBuffer = ChartsHelper::GetCollisionBuffer(charts); long offsetX = ChartsHelper::GetOffsetX(charts); long offsetY = ChartsHelper::GetOffsetY(charts); diff --git a/src/Drawing/ShapefileDrawing.cpp b/src/Drawing/ShapefileDrawing.cpp index 41e13df9..42051b9a 100644 --- a/src/Drawing/ShapefileDrawing.cpp +++ b/src/Drawing/ShapefileDrawing.cpp @@ -62,7 +62,6 @@ enum tkDrawingShape bool CShapefileDrawer::Draw(const CRect & rcBounds, IShapefile* sf) { if (!sf) return false; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); _shapefile = reinterpret_cast(sf); diff --git a/src/Editor/GroupOperation.cpp b/src/Editor/GroupOperation.cpp index ea4bc34c..0dacd324 100644 --- a/src/Editor/GroupOperation.cpp +++ b/src/Editor/GroupOperation.cpp @@ -17,7 +17,6 @@ bool GroupOperation::Run(tkCursorMode cursorMode, long layerHandle, IShapefile* errorCode = tkUNEXPECTED_NULL_PARAMETER; return false; } - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); vector indices; if (!SelectionHelper::SelectWithShapeBounds(sf, shp, indices)) @@ -54,8 +53,6 @@ bool GroupOperation::Run(tkCursorMode cursorMode, long layerHandle, IShapefile* // *************************************************************** bool GroupOperation::ClipByPolygon(tkCursorMode cursorMode, long layerHandle, IShapefile* sf, vector& indices, IShape*polygon, IUndoList* undoList, int& errorCode) { - if (!sf) return false; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); GEOSGeometry* gPoly = GeosConverter::ShapeToGeom(polygon); if (!gPoly) { errorCode = tkCANT_CONVERT_SHAPE_GEOS; @@ -151,8 +148,6 @@ bool GroupOperation::ClipByPolygon(tkCursorMode cursorMode, long layerHandle, IS bool GroupOperation::SplitByPolyline(long layerHandle, IShapefile* sf, vector& indices, IShape* polyline, IUndoList* undoList, int& errorCode) { - if (!sf) return false; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); vector deleteList; long mwShapeIdIndex = ShapefileHelper::GetMWShapeIdIndex(sf); diff --git a/src/InnoSetup/MapWinGIS-only.iss b/src/InnoSetup/MapWinGIS-only.iss index 9fb063a6..ee4bdd76 100644 --- a/src/InnoSetup/MapWinGIS-only.iss +++ b/src/InnoSetup/MapWinGIS-only.iss @@ -2,12 +2,12 @@ ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "MapWinGIS" -#define MyAppVersion "5.1.0" +#define MyAppVersion "5.1.1" #define MyAppPublisher "MapWindow Open Source GIS Community" #define MyAppURL "http://www.mapwindow.org" #define SetupLocation "D:\dev\MapWindow\MapWinGIS\git\src\InnoSetup" #define BinLocation "D:\dev\MapWindow\MapWinGIS\git\src\bin" -;; #define x64BitVersion +;#define x64BitVersion ;; #define VsVersion = "2015" #define VsVersion = "2017" @@ -80,8 +80,9 @@ Source: "{#MySourceDir}\MapWinGIS.ocx"; DestDir: "{app}"; Flags: ignoreversion { ;; IntelliSense: Source: "{#SetupLocation}\AxInterop.MapWinGIS.XML"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core Source: "{#SetupLocation}\Interop.MapWinGIS.XML"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core -;; Delphi TAB file +;; Delphi files Source: "{#SetupLocation}\MapWinGIS_TLB.pas"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Delphi +Source: "{#SetupLocation}\MapWinGIS.Delphi.Component.v5.1.0.zip"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Delphi ;; Licenses Source: "{#BinLocation}\Licenses\GDALLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core Source: "{#BinLocation}\Licenses\GISInternalsLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core diff --git a/src/InnoSetup/MapWinGIS.Delphi.Component.v5.1.0.zip b/src/InnoSetup/MapWinGIS.Delphi.Component.v5.1.0.zip new file mode 100644 index 00000000..12ced5ba Binary files /dev/null and b/src/InnoSetup/MapWinGIS.Delphi.Component.v5.1.0.zip differ diff --git a/src/InnoSetup/MapWinGIS_TLB.pas b/src/InnoSetup/MapWinGIS_TLB.pas index 80456478..dd4e83ba 100644 Binary files a/src/InnoSetup/MapWinGIS_TLB.pas and b/src/InnoSetup/MapWinGIS_TLB.pas differ diff --git a/src/MapWinGIS.idl b/src/MapWinGIS.idl index e365653f..65ab9d58 100644 --- a/src/MapWinGIS.idl +++ b/src/MapWinGIS.idl @@ -6834,6 +6834,7 @@ library MapWinGIS [id(212), propget] float Latitude(); [id(213), propput] void Longitude(float nNewValue); [id(213), propget] float Longitude(); + [id(267)] void SetLatitudeLongitude(double latitude, double longitude); [id(218), propput] void KnownExtents(tkKnownExtents nNewValue); [id(218), propget] tkKnownExtents KnownExtents(); #endif diff --git a/src/MapWinGIS.rc b/src/MapWinGIS.rc index cdf815c0..e47bbd3f 100644 --- a/src/MapWinGIS.rc +++ b/src/MapWinGIS.rc @@ -112,8 +112,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 5,1,0,0 - PRODUCTVERSION 5,1,0,0 + FILEVERSION 5,1,1,0 + PRODUCTVERSION 5,1,1,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -131,13 +131,13 @@ BEGIN VALUE "Comments", "This control includes a mapping component and objects for reading and writing shapefiles and various triangulated irregular network and grid files. It also has extensive label and chart options and includes projection routines." VALUE "CompanyName", "MapWindow OSS Team - www.mapwindow.org" VALUE "FileDescription", "MapWinGIS ActiveX Control" - VALUE "FileVersion", "5.1.0.0" + VALUE "FileVersion", "5.1.1.1" VALUE "InternalName", "MapWinGIS ActiveX Control" VALUE "LegalCopyright", "Copyright (C) 2004-2019 MapWindow OSS Team" VALUE "LegalTrademarks", "MapWindow GIS is a trademark of Daniel P. Ames, 2005-2019" VALUE "OriginalFilename", "MapWinGIS.ocx" VALUE "ProductName", "MapWinGIS ActiveX Control" - VALUE "ProductVersion", "5.1.0.0" + VALUE "ProductVersion", "5.1.1.1" END END BLOCK "VarFileInfo" diff --git a/src/Ogr/Ogr2RawData.cpp b/src/Ogr/Ogr2RawData.cpp index 77afe745..2c8ca95f 100644 --- a/src/Ogr/Ogr2RawData.cpp +++ b/src/Ogr/Ogr2RawData.cpp @@ -8,7 +8,7 @@ // ************************************************************* // Layer2RawData() // ************************************************************* -bool Ogr2RawData::Layer2RawData(OGRLayer* layer, Extent* extents, OgrDynamicLoader* loader, OgrLoadingTask* callback) +bool Ogr2RawData::Layer2RawData(OGRLayer* layer, Extent* extents, OgrDynamicLoader* loader, OgrLoadingTask* callback) { if (!layer || !extents || !loader) return false; @@ -58,7 +58,6 @@ bool Ogr2RawData::Layer2RawData(OGRLayer* layer, Extent* extents, OgrDynamicLoad // Get shape record: ShapeRecordData* data = new ShapeRecordData(); shp->ExportToBinary(&(data->Shape), &vb); - shp->Release(); FieldsToShapeRecord(poFields, poFeature, data, hasFID); diff --git a/src/Ogr/Ogr2RawData.h b/src/Ogr/Ogr2RawData.h index c7941237..e1646ec9 100644 --- a/src/Ogr/Ogr2RawData.h +++ b/src/Ogr/Ogr2RawData.h @@ -7,9 +7,9 @@ class Ogr2RawData { -public: + public: static bool Ogr2RawData::Layer2RawData(OGRLayer* layer, Extent* extents, OgrDynamicLoader* loader, OgrLoadingTask* callback); -private: + private: static void Ogr2RawData::FieldsToShapeRecord(OGRFeatureDefn* poFields, OGRFeature* poFeature, ShapeRecordData* data, bool hasFid); static void DeleteAndClearShapeData(vector& data); }; diff --git a/src/Ogr/Ogr2Shape.cpp b/src/Ogr/Ogr2Shape.cpp index 5c7da73f..4a3e306f 100644 --- a/src/Ogr/Ogr2Shape.cpp +++ b/src/Ogr/Ogr2Shape.cpp @@ -110,9 +110,6 @@ IShapefile* Ogr2Shape::CreateShapefile(OGRLayer* layer, ShpfileType activeShapeT // ************************************************************* void Ogr2Shape::CopyFields(OGRLayer* layer, IShapefile* sf) { - if (!sf) return; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - IField * fld = NULL; VARIANT_BOOL vb; @@ -169,7 +166,6 @@ void Ogr2Shape::CopyFields(OGRLayer* layer, IShapefile* sf) tableInternal->SetFieldSourceIndex(i, i - 1); } } - // ************************************************************* // ExtendShapefile() // ************************************************************* @@ -294,7 +290,6 @@ bool Ogr2Shape::ExtendShapefile(OGRLayer* layer, IShapefile* sf, bool loadLabels bool Ogr2Shape::FillShapefile(OGRLayer* layer, IShapefile* sf, int maxFeatureCount, bool loadLabels, ICallback* callback, bool& isTrimmed) { if (!sf || !layer) return false; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); layer->ResetReading(); @@ -402,9 +397,6 @@ bool isXBaseLogicalTrue(wchar_t c) void Ogr2Shape::CopyValues(OGRFeatureDefn* poFields, OGRFeature* poFeature, IShapefile* sf, bool hasFID, long numShapes, bool loadLabels, OgrLabelsHelper::LabelFields labelFields) { - if (!sf) return; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); - double x = 0.0, y = 0.0, rotation = 0; CStringW text; diff --git a/src/Ogr/OgrLoader.cpp b/src/Ogr/OgrLoader.cpp index 9c898a64..cdc9518b 100644 --- a/src/Ogr/OgrLoader.cpp +++ b/src/Ogr/OgrLoader.cpp @@ -116,11 +116,11 @@ void OgrDynamicLoader::AwaitTasks() queueLock.Lock(); continue; // Try next } - else + else { delete task; } - } + } } // ********************************************** diff --git a/src/Ogr/OgrLoader.h b/src/Ogr/OgrLoader.h index d17c4611..51fe3101 100644 --- a/src/Ogr/OgrLoader.h +++ b/src/Ogr/OgrLoader.h @@ -57,6 +57,7 @@ class OgrDynamicLoader vector Data; public: + ::CCriticalSection ShapefileLock; ::CCriticalSection LoadingLock; ::CCriticalSection ProviderLock; diff --git a/src/Ogr/Shape2Ogr.cpp b/src/Ogr/Shape2Ogr.cpp index bce76a65..84881fa0 100644 --- a/src/Ogr/Shape2Ogr.cpp +++ b/src/Ogr/Shape2Ogr.cpp @@ -13,8 +13,6 @@ // ************************************************************* bool Shape2Ogr::Shapefile2OgrLayer(IShapefile* sf, OGRLayer* poLayer, bool saveLabels, ICallback* callback /*= NULL*/) { - if (!sf) return false; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); ShapefileFieldsToOgr(sf, poLayer); if (m_globalSettings.saveOgrLabels) { @@ -400,7 +398,6 @@ int Shape2Ogr::SaveShapefileChanges(OGRLayer* layer, IShapefile* sf, long shapeC errors.clear(); if (!sf || !layer || shapeCmnIndex == -1) return 0; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); OGRFeatureDefn* fields = layer->GetLayerDefn(); int fieldCount = fields->GetFieldCount(); diff --git a/src/Processing/ClipperConverter.cpp b/src/Processing/ClipperConverter.cpp index b80fc6f3..614b6af1 100644 --- a/src/Processing/ClipperConverter.cpp +++ b/src/Processing/ClipperConverter.cpp @@ -268,7 +268,6 @@ IShape* ClipperConverter::ClipPolygon(IShape* shapeClip, IShape* shapeSubject, P void ClipperConverter::AddPolygons(IShapefile* sf, ClipperLib::Clipper& clp, ClipperLib::PolyType clipType, bool selectedOnly) { if (!sf) return; - CSingleLock sfLock(&((CShapefile*)sf)->ShapefileLock, TRUE); long numShapes; sf->get_NumShapes(&numShapes); diff --git a/src/Shapefile/GeoProcessing.cpp b/src/Shapefile/GeoProcessing.cpp index 96a30b68..fb616e08 100644 --- a/src/Shapefile/GeoProcessing.cpp +++ b/src/Shapefile/GeoProcessing.cpp @@ -9,19 +9,16 @@ // **************************************************************** void GeoProcessing::CopyFields(IShapefile* sfSubject, IShapefile* sfOverlay, IShapefile* sfResult, map& fieldMap, bool mergeFields) { - if (!sfSubject || !sfOverlay || !sfResult) return; // fields of the subject shapefile LONG numFields, position; VARIANT_BOOL vbretval; sfSubject->get_NumFields(&numFields); - CSingleLock sfSubjectLock(&((CShapefile*)sfSubject)->ShapefileLock, TRUE); - CSingleLock sfOverlayLock(&((CShapefile*)sfOverlay)->ShapefileLock, TRUE); - CSingleLock sfResultLock(&((CShapefile*)sfResult)->ShapefileLock, TRUE); ShapefileHelper::CopyFields(sfSubject, sfResult); // passing the fields of overlay shapefile if (sfOverlay) { + LONG numFields2; sfOverlay->get_NumFields(&numFields2); for (long i = 0; i < numFields2; i++) diff --git a/src/Shapefile/ShapeInterfaces.cpp b/src/Shapefile/ShapeInterfaces.cpp index fdef204d..662dc79e 100644 --- a/src/Shapefile/ShapeInterfaces.cpp +++ b/src/Shapefile/ShapeInterfaces.cpp @@ -48,14 +48,14 @@ void IShapeWrapper::CopyTo(IShapeWrapper* target) for (int i = 0; i < get_PartCount(); i++) { int part = get_PartStartPoint(i); - target->put_PartStartPoint(i, part); + target->InsertPart(i, part); } double x, y, z, m; for (int i = 0; i < get_PointCount(); i++) { get_PointXY(i, x, y); - target->put_PointXY(i, x, y); + target->InsertPointXY(i, x, y); if (isM || isZ) { diff --git a/src/Structures/Layer.cpp b/src/Structures/Layer.cpp index 4df04e22..43a69156 100644 --- a/src/Structures/Layer.cpp +++ b/src/Structures/Layer.cpp @@ -384,10 +384,12 @@ UINT OgrAsyncLoadingThreadProc(LPVOID pParam) // Fire event for this task: OgrLoadingTask* task = options->task; - task->Finished = true; - task->Cancelled = !success; + task->Finished = true; + task->Cancelled = !success; options->map->_FireBackgroundLoadingFinished(task->Id, task->LayerHandle, task->FeatureCount, 0); + loader->ClearFinishedTasks(); + } layer->put_AsyncLoading(false); Debug::WriteWithThreadId("Releasing loading lock. \n", DebugOgrLoading); @@ -422,7 +424,9 @@ void Layer::LoadAsync(IMapViewCallback* mapView, Extent extents, long layerHandl // This prevents race condition between the started & completed event. AsyncLoadingParams* param = new AsyncLoadingParams(mapView, extents, this, task); mapView->_FireBackgroundLoadingStarted(task->Id, layerHandle); - CWinThread* thread = AfxBeginThread(OgrAsyncLoadingThreadProc, (LPVOID)param); + OgrAsyncLoadingThreadProc(param); + + //CWinThread* thread = AfxBeginThread(OgrAsyncLoadingThreadProc, (LPVOID)param); } //*********************************************************************** @@ -435,9 +439,10 @@ void Layer::UpdateShapefile() // Get the OGR layer: IOgrLayer* layer = NULL; - if (!QueryOgrLayer(&layer)) return; - - ((COgrLayer*) layer)->UpdateShapefileFromOGRLoader(); + if (!QueryOgrLayer(&layer)) + return; + + ((COgrLayer*)layer)->UpdateShapefileFromOGRLoader(); } //****************************************************