Following on from an earlier discussion I have been trying out using SQLite for a custom layer (just lines and polygons at the moment). I based my new layer on the example ExtendingMapSuiteFeatureSource and it works really well however my new layer does not appear to have a bounding box. As a guess I tried overriding GetBoundingBoxCore in the new feature source class but that didn’t help as it doesn’t seem to get called from anywhere.
Could you help me with setting the bounding box for my new layer?
Regards,
Jonathan
SQLite Layer
Hi Jonathan,
Sorry I haven’t find original post, and if I misunderstand your question please let me know.
Do you meant you modify our sample ExtendingMapSuiteFeatureSource to render your layer, and your layer data is saved in SQLite.
This layer can be render well, but GetBoundingBox function don’t works, is that right?
Any sample or more exactly information should be helpful.
Regards,
Don
Don,
Your description is exactly right. The layer renders well but get bounding box for the layer returns an error as the bounding box is not defined.
The code for the feature source layer is:
(Not I added the override to GetBoundingBoxCore as an attempt to fix the getBoundingBox error.
using
System;
using
System.Collections.Generic;
using
System.Collections.ObjectModel;
using
System.Linq;
using
System.Text;
using
System.Data.SQLite;
using
ThinkGeo.MapSuite.Core;
namespace
PTSimpleMapper
{
class
clsPearFeatureSource : FeatureSource
{
private
SQLiteConnection pearConnection =
new
SQLiteConnection();
// Default constructor
// Should chain to a more complex constructor when add more functionality
public
clsPearFeatureSource() { }
// OVERRIDE STANDARD FUNCTIONS
// Open core
protected
override
void
OpenCore()
{
pearConnection =
new
SQLiteConnection(@
“Data Source=C:\Users\Jonathan\Documents\Visual Studio 2008\Projects\TestSQLite\TestSQLite\bin\Debug\myTestDB.db”
);
pearConnection.Open();
}
// Close core
protected
override
void
CloseCore()
{
pearConnection.Close();
}
protected
override
Collection<Feature> GetAllFeaturesCore(IEnumerable<
string
> returningColumnNames)
{
Collection<Feature> rtn =
new
Collection<Feature>();
string
theSQL =
“SELECT Key, Value FROM Setting”
;
SQLiteCommand getAllFeatures =
new
SQLiteCommand(theSQL, pearConnection);
try
{
using
(SQLiteDataReader reader = getAllFeatures.ExecuteReader())
{
while
(reader.Read())
{ rtn.Add(
new
Feature(reader[
“Value”
].ToString())); }
}
}
finally
{
if
(!getAllFeatures.Equals(
null
)) { getAllFeatures.Dispose(); }
}
return
rtn;
}
protected
override
Collection<Feature> GetFeaturesInsideBoundingBoxCore(RectangleShape boundingBox, IEnumerable<
string
> returningColumnNames)
{
Collection<Feature> rtn =
new
Collection<Feature>();
string
theSQL =
string
.Format(
“SELECT Key, Value FROM Setting WHERE”
+
" NOT (LR_Y >= {0}) AND NOT (UL_Y <= {1}) AND NOT (LR_X <= {2}) AND NOT (UL_X >= {3})"
,
boundingBox.UpperLeftPoint.Y,
boundingBox.LowerRightPoint.Y,
boundingBox.UpperLeftPoint.X,
boundingBox.LowerRightPoint.X);
SQLiteCommand getAllFeatures =
new
SQLiteCommand(theSQL, pearConnection);
try
{
using
(SQLiteDataReader reader = getAllFeatures.ExecuteReader())
{
while
(reader.Read())
{ rtn.Add(
new
Feature(reader[
“Value”
].ToString())); }
}
}
finally
{
if
(!getAllFeatures.Equals(
null
)) { getAllFeatures.Dispose(); }
}
return
rtn;
}
protected
override
RectangleShape GetBoundingBoxCore()
{
RectangleShape rtn =
new
RectangleShape();
string
[] theSQL =
new
string
[4] {
“SELECT MAX(UL_Y) FROM Settings”
,
“SELECT MIN(LR_Y) FROM Settings”
,
“SELECT MAX(LR_X) FROM Settings”
,
“SELECT MIN(UL_X) FROM Settings”
};
double
[] theLimits =
new
double
[4] { 0, 0, 0, 0 };
try
{
theLimits[0] = Convert.ToInt32(
new
SQLiteCommand(theSQL[0], pearConnection).ExecuteScalar());
theLimits[1] = Convert.ToInt32(
new
SQLiteCommand(theSQL[1], pearConnection).ExecuteScalar());
theLimits[2] = Convert.ToInt32(
new
SQLiteCommand(theSQL[2], pearConnection).ExecuteScalar());
theLimits[3] = Convert.ToInt32(
new
SQLiteCommand(theSQL[3], pearConnection).ExecuteScalar());
PointShape ul =
new
PointShape(theLimits[4], theLimits[1]);
PointShape lr =
new
PointShape(theLimits[3], theLimits[2]);
rtn =
new
RectangleShape(ul, lr);
}
finally
{
}
return
rtn;
}
protected
override
int
GetCountCore()
{
int
rtn = 0;
string
theSQL =
“SELECT COUNT(*) FROM Setting”
;
SQLiteCommand getCount =
new
SQLiteCommand(theSQL, pearConnection);
try
{
rtn = Convert.ToInt32(getCount.ExecuteScalar());
}
finally
{
if
(!getCount.Equals(
null
)) { getCount.Dispose(); }
}
return
rtn;
}
}
}
The error I get when trying “theMap.CurrentExtent = theOverlay.Layers.First().GetBoundingBox();” is:
System.NotSupportedException was unhandled
Message=“This Layer doesn’t have a boundingBox.”
Source=“MapSuiteCore”
StackTrace:
at ohM=.TFA=.ZVE=(Boolean ZlE=)
at ThinkGeo.MapSuite.Core.Layer.GetBoundingBox()
at PTSimpleMapper.clsProjectSupport.findFirstBoundingBox(WinformsMap& theMap, LayerOverlay& theOverlay) in C:\Users\Jonathan\Documents\Visual Studio 2008\Projects\simpleMapper\simpleMapper\MapProject\clsProjectSupport.cs:line 383
at PTSimpleMapper.clsProjectSupport.showFullExtent(WinformsMap& theMap, LayerOverlay& theOverlay) in C:\Users\Jonathan\Documents\Visual Studio 2008\Projects\simpleMapper\simpleMapper\MapProject\clsProjectSupport.cs:line 368
at PTSimpleMapper.clsProjectSupport.showFullExtent(WinformsMap& theMap) in C:\Users\Jonathan\Documents\Visual Studio 2008\Projects\simpleMapper\simpleMapper\MapProject\clsProjectSupport.cs:line 478
at PTSimpleMapper.frmMap.anyNavigationButton_Click(Object sender, EventArgs e) in C:\Users\Jonathan\Documents\Visual Studio 2008\Projects\simpleMapper\simpleMapper\Forms and Dialogs\frmMap.cs:line 1103
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at PTSimpleMapper.Program.Main() in C:\Users\Jonathan\Documents\Visual Studio 2008\Projects\simpleMapper\simpleMapper\Program.cs:line 18
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
Regards,
Jonathan
I may have solved this one, but I would like to know if I’m going about it the right way?
In the featureLayer I did a simple override of HasBoundingBox to return TRUE. This resulted in the FeatureSource function GetBoundingBoxCore being called. There were a few errors in my code for this function but they were quite easy to fix.
Is it OK to simply return TRUS? or should I be doing some sort of check or something for HasBoundingBox?
Regards,
Jonathan
Hi Jonathan,
I think you are right, as below is the description about HasBoundingBox:
This property indicates whether a Layer has a BoundingBox or not. If it has no BoundingBox, it will throw an exception when you call the GetBoundingBox() and GetFullExtent() APIs.
So just override HasBoundingBox is OK.
public override bool HasBoundingBox
{
get { return true; }
}
Regards,
Don
Don,
OK, thanks. I did think I might put in one simple check and only return true for HasBoundingBox if the count of features is not zero.
All the best,
Jonathan
Jonathan,
You can just return a new RectangleShape if the feature number is zero in GetBoundingBoxCore.
Regards,
Don
Don,
Thank you, that makes good sense.
Regards,
Jonathan
Jonathan,
I am glad to know my reply helpful, any question please let us know.
Reagards,
Don