How does one query "Features" from SQL database within a user drawn shape ?
Spatial Query of features Based on User Drawn Shape
Can you give a little more context? What type of SQL database are you using and how is the geographic info stored? With more information on your system we should be able to give you a more detailed answer. Thank you.
My data is stored in SQL 2005 as follows:
X Y col1 col2
27.9605 -26.0931 B House
27.9606 -26.0932 B House
27.9607 -26.0935 A House
27.9609 -26.0936 B House
27.961 -26.0938 A House
27.9612 -26.0941 B House
------------------------------------------------
Basically a user will go to a city select an area or draw a shape which selects an area of houses.
I need to return the points/features/houses(not sure what you call them) that are inside the shape they have drawn.
Michael,
I think you can not use our Mssql2008FeatureLayer, because it supports spatial data that means your table should have a column which data type is either Geometry or Geography, otherwise it’s only a normal table we can not implement spatial query.
Please look at aricle below you will get more detail about what I am saying:
microsoft.com/sqlserver/2008/en/us/spatial-data.aspx
Thanks,
James
The data i have shown you is from a MapInfo export to CSV then from CSV import into SQL
They are points plotted on MapInfo.
Can i export from MapInfo to include the "Geometry or Geography" as you mentioned?
Michael,
I am sorry I am not familiar with MapInfo so I don’t know if you can export from it to include the spatial data column, I did a little research but still don’t find any way can do it.
There is another way to implement your requirement, we can create a custom feature source that support CSV file directly. You can find the sample “Extending Map Suite: Integrating Custom Data Formats - 10/29/2008” at following page, it includes video, presentation sides, source code and Q&A transcript.
gis.thinkgeo.com/Products/GI...fault.aspx
Thanks,
James
What does the spatial data look like? Geometry ? Geography?
What Point data is required by MapSuite to query a specified area for points within that area?
I did an import of the MAP INFO TAB file using EasyLoader.exe and got the below
X Y Income_Group Type_Dwelling Datestamp MI_STYLE MI_SQL_REC_NUM MI_SQL_X MI_SQL_Y MI_SQL_MICODE
27.923951 -32.967174 A House 2010 null 1 27.923951 -32.967174 AJBIDKJPDIKBKEOMF
27.924721 -32.967046 B House 2010 null 2 27.924721 -32.967046 AJBIDKJPDKBCCEJMG
27.924906 -32.96725 B House 2010 null 3 27.924906 -32.96725 AJBIDKJPCPFNDGLJE
27.929363 -32.966663 B House 2010 null 4 27.929363 -32.966663 AJBIDKJPJAPBCDCFK
27.929689 -32.966789 B House 2010 null 5 27.929689 -32.966789 AJBIDKJPJAOMAOIPE
27.929179 -32.966993 A House 2010 null 6 27.929179 -32.966993 AJBIDKJPJAJLDEAMM
27.928784 -32.966649 A House 2010 null 7 27.928784 -32.966649 AJBIDKJPJANBLODGG
27.928349 -32.967261 A House 2010 null 8 27.928349 -32.967261 AJBIDKJPIFHNCMLAK
27.928157 -32.967564 A House 2010 null 9 27.928157 -32.967564 AJBIDKJPIFGCCBLIG
27.92286 -32.965543 C House 2010 null 10 27.92286 -32.965543 AJBIDKJPDMDNCOFIL
27.927153 -32.969168 A House 2010 null 11 27.927153 -32.969168 AJBIDKJPCLKOGPDCB
27.927295 -32.968865 A+ House 2010 null 12 27.927295 -32.968865 AJBIDKJPIBEBHAIFP
27.927471 -32.968549 A+ House 2010 null 13 27.927471 -32.968549 AJBIDKJPIEADCEKKH
27.927738 -32.968134 B House 2010 null 14 27.927738 -32.968134 AJBIDKJPIEEMPCPCJ
27.927889 -32.967817 A House 2010 null 15 27.927889 -32.967817 AJBIDKJPIFAOIOPNL
27.927639 -32.969392 A House 2010 null 16 27.927639 -32.969392 AJBIDKJPIAFJDFNCK
Michael,
I can respond to your last post about finding the points inside an area shape. I wrote some code using your example ( Johannesburg, South Africa according to the coordinates) to show how to find the points within an ellipse of 32 meters of radius as you can see on the screenshot. You can see that I am using PointShapes and you can get the X and Y from your database.
Look at the code:
Collection<PointShape> pointShapes = new Collection<PointShape>();
pointShapes.Add(new PointShape(27.9605,- 26.0931));
pointShapes.Add(new PointShape(27.9606, - 26.0932));
pointShapes.Add(new PointShape(27.9607, - 26.0935));
pointShapes.Add(new PointShape(27.9609, - 26.0936));
pointShapes.Add(new PointShape(27.961, - 26.0938));
pointShapes.Add(new PointShape(27.9612, - 26.0941));
//InMemoryFeatureLayer for the points
InMemoryFeatureLayer inMemoryFeatureLayer = new InMemoryFeatureLayer();
inMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.CreateSimplePointStyle(PointSymbolType.Circle,
GeoColor.FromArgb(150, GeoColor.StandardColors.Red), 12);
inMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.CreateSimpleAreaStyle(GeoColor.FromArgb(100, GeoColor.StandardColors.Green),
GeoColor.StandardColors.Black);
inMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
foreach (PointShape pointShape in pointShapes)
{
inMemoryFeatureLayer.InternalFeatures.Add(new Feature(pointShape));
}
//InMemoryFeatureLayer for the area shape
InMemoryFeatureLayer inMemoryFeatureLayer2 = new InMemoryFeatureLayer();
inMemoryFeatureLayer2.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.CreateSimpleAreaStyle(GeoColor.FromArgb(100, GeoColor.StandardColors.Green),
GeoColor.StandardColors.Black);
inMemoryFeatureLayer2.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
//Ellipse of a radius of 32 meter that is used for finding points inside.
EllipseShape ellipseShape = new EllipseShape(new PointShape(27.9608, -26.0934), 32, Map1.MapUnit, DistanceUnit.Meter);
inMemoryFeatureLayer2.InternalFeatures.Add(new Feature(ellipseShape));
//InMemoryFeatureLayer for the points inside the area shape
InMemoryFeatureLayer selectInMemoryFeatureLayer = new InMemoryFeatureLayer();
selectInMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.CreateSimplePointStyle(PointSymbolType.Circle,
GeoColor.FromArgb(150, GeoColor.StandardColors.Yellow), 12);
selectInMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
//Spatial Query to find the points inside the area shape.
inMemoryFeatureLayer.Open();
Collection<Feature> selectFeatures = inMemoryFeatureLayer.QueryTools.GetFeaturesWithin(ellipseShape, ReturningColumnsType.NoColumns);
inMemoryFeatureLayer.Close();
foreach (Feature selectFeature in selectFeatures)
{
selectInMemoryFeatureLayer.InternalFeatures.Add(selectFeature);
}
LayerOverlay dynamicOverlay = new LayerOverlay();
dynamicOverlay.Layers.Add(inMemoryFeatureLayer);
dynamicOverlay.Layers.Add(inMemoryFeatureLayer2);
dynamicOverlay.Layers.Add(selectInMemoryFeatureLayer);
Map1.CustomOverlays.Add(dynamicOverlay);
inMemoryFeatureLayer.Open();
Map1.CurrentExtent = inMemoryFeatureLayer.GetBoundingBox();
inMemoryFeatureLayer.Close();
Thank you Val so very much for this.
Because i have many point shapes and only the point shapes that are found within the area must be shown. Is that possible?
Michael,
I guess you want to only show the points within area, not show the points without area, right?
Val’s sample is almost done all you want, you can remove inMemoryFeatureLayer, just keep inMemoryFeatureLayer2 and selectInMemoryFeatureLayer.
Thanks,
James
How many "pointShapes" can you load into memory before you start to lose performance?
If i have a user zoomed into a small secton of the map and there are points outside of his screen he is zoomed in on. Will those points need to be loaded into memory as well?
Michael,
I can’t tell you a explicit number. Because the performance depends on your hardware largely. Different machine has a different result. The more pointShape you added, the more memory will be taken up. And if you has amount of points need to add, you can improve performance by cache it.
The points outside of screen won’t be loaded into memory.
Thanks,
James
Michael,
Here is a little clarification, I hope it helps.
If you use an InMemoryFeatureLayer then of course all the points are in memory. We do not draw all of those points, just the ones in the current extent. We create an in-memory R-Tree index so that we can quickly know the points in the current extent. Using the index we can easily scale to millions of features as long as you have the free ram to keep all of those in memory. The performance of displaying a subset that is in the extent should not be a problem. The point where the performance degrades so much depends on memory and machine performance.
I was reviewing the code that Val posted and I noticed that he is not building the spatial index. After you add all of the features to the InternalFeatures collection you need to call the InMemoryFeatureLayer.BuildIndex. This will cause the R-Tree index to be build and used. If you do not call the BuildIndex then on every render we need to loop through each feature and see if it is in the extent. For small collections this is not a problem but when you load a large volume of data I suggest you always use the BuildIndex method after adding your features.
If you were using a ShapeFileFeatureLayer or other kinds then we use spatial indexes to load into memeory just the features that are going to be displayed. In this way you could have a multi gig shapefile and using index we can quickly get the items in the extent.
Thanks,
David
Thank you guys so much!
James that answers some critical concerns i had.
David that really does clear up a few things. Is it not possible to Load the points into memory with an existing index?
Also, with the points loaded into server memory, does that mean that 50-100 people can view the map with the points and it just needs to be in memory once for all people?
Michael,
Actually the points are stored in the collection. It is loaded into memory with an existing index.
No. If 100 people view the map, there will be 100 sessions. Each session will be converted to InMemoryFeatureLayer.
Thanks,
James
I dont understand "Each session will be converted to InMemoryFeatureLayer. "
Michael,
What I want to say is we need to create a session for each user and in code, we need to convert the "Session" Object to an InMemoryFeatureLayer, like following. :)
InMemoryFeatureLayer inMemoryFeatureLayer = (InMemoryFeatureLayer)context.Session[id];
Thanks,
James