Hi, I am working on a application developed on .NET platform that interacts with ArcMap, and I would like to know if the proposed process I need to develop can be done or not. If can, how to do it. Your help and advices are highly appreciated.
Basically, we have a feature class in ArcSDE that contains about 20 million of points. Each point feature has a "NAME" field, and normally around 50 - 2000 points are associated with one pacific NAME value. I have developed a form using VB.NET to allow user to input the NAME value they would like to show on the map. My question is: how can I select a subset of the point features based on the user input and display them as a layer in ArcMap.
As I mentioned before, there are huge volume of point features, so I don't want to load the whole feature class into ArcMap - it takes ages to draw. I only want to select a subset of the points from ArcSDE feature class, and show these points in map. Is this difficult to do? I haven't found any relevant information on the net so far.
Please let me know if I didn't explain the question clearly. Thanks in advance for your help!
Hi Richard, thank you very much for your reply and the suggestions are very helpful.
I am looking to apply a definition query on the data not a select layer. As background info, the point feature class contains the locations of trucks collected every 15 seconds, and the table is updated quite frequently (not real-time tho). There is a master table of the data contains X,Y coordinates for location, and we spatilaise the data into a SDE feature class using these coordinates. The reason we doing so is that we hope this can speed up the drawing. I assume it will take longer time to create points on the fly using X,Y coordinates. Please correct me if I'm wrong. Honestly, I still do not have a clear picture how this thing will work out.
I guess what I wanted to do is "open an SDE connection in memory without a layer and only create a prefiltered layer with a definition query", could you please provide me some more info/sample code how to do this?
If you have any other better solutions, please advice. Many thanks!
Option Explicit Public Sub AddSDECoverageLayer(byRef TruckID As String) Dim pWorkFact As IWorkspaceFactory2 Dim pFWorkspace As IFeatureWorkspace Dim pFClass As IFeatureClass Dim pFLayer As IFeatureLayer Dim pMxDoc As IMxDocument Dim pMap As IMap Dim pAV As IActiveView 'Open Feature Class Set pWorkFact = New SdeWorkspaceFactory Set pFWorkspace = pWorkFact.OpenFromString("server=luxor;instance=5156;user=avuser;password=avtest", 0) Set pFClass = pFWorkspace.OpenFeatureClass("TruckPoints") 'Create new layer Set pFLayer = New FeatureLayer Set pFLayer.FeatureClass = pFClass pFLayer.Name = pFClass.AliasName & " TruckID " & TruckID ' Define a definition query for the layer from the input variable Dim pFeatDef As IFeatureLayerDefinition Set pFeatDef = pFLayer pFDef.DefinitionExpression = "TRUCKID = '" & TruckID & "'" ' Build a real Query by Attribute that works. Remove single quotes if the field is not a Text field. 'Add layer to map Set pMxDoc = ThisDocument Set pMap = pMxDoc.FocusMap Set pAV = pMap pMap.AddLayer pFLayer pAV.Refresh End Sub
Public Function CreateQueryTable(ByVal workspace As IWorkspace, ByVal queryDef As IQueryDef, ByVal tableName As String) As ITable ' Create a reference to a TableQueryName object. Dim queryName2 As IQueryName2 = New TableQueryNameClass() queryName2.PrimaryKey = "" ' Specify the query definition. queryName2.QueryDef = queryDef ' Get a name object for the workspace. Dim dataset As IDataset = CType(workspace, IDataset) Dim workspaceName As IWorkspaceName = CType(dataset.FullName, IWorkspaceName) ' Cast the TableQueryName object to the IDatasetName interface and open it. Dim datasetName As IDatasetName = CType(queryName2, IDatasetName) datasetName.WorkspaceName = workspaceName datasetName.Name = tableName Dim Name As IName = CType(datasetName, IName) ' Open the name object and get a reference to a table object. Dim table As ITable = CType(Name.Open(), ITable) Return table End Function
The only problem I found is that if I would like to zoom to the layer extent with definition query, it always zoom to the full extent of the layer. After investigation, I found some code to loop through all the features and join the extent together to get the correct extent. However when large number of points (over 5000 pts) encountered, this method will take significant amount of time (over 20 secs). Do you have any better idea which can get the extent faster?
Option Explicit Public Sub AddSDECoverageLayer(byRef TruckID As String) Dim pWorkFact As IWorkspaceFactory2 Dim pFWorkspace As IFeatureWorkspace Dim pFClass As IFeatureClass Dim pFLayer As IFeatureLayer Dim pMxDoc As IMxDocument Dim pMap As IMap Dim pAV As IActiveView 'Open Feature Class Set pWorkFact = New SdeWorkspaceFactory Set pFWorkspace = pWorkFact.OpenFromString("server=luxor;instance=5156;user=avuser;password=avtest", 0) Set pFClass = pFWorkspace.OpenFeatureClass("TruckPoints") 'Create new layer Set pFLayer = New FeatureLayer Set pFLayer.FeatureClass = pFClass pFLayer.Name = pFClass.AliasName & " TruckID " & TruckID ' Define a definition query for the layer from the input variable Dim pFeatDef As IFeatureLayerDefinition Set pFeatDef = pFLayer pFDef.DefinitionExpression = "TRUCKID = '" & TruckID & "'" ' Build a real Query by Attribute that works. Remove single quotes if the field is not a Text field. 'Add layer to map Set pMxDoc = ThisDocument Set pMap = pMxDoc.FocusMap Set pAV = pMap pMap.AddLayer pFLayer ' After you have applied your definition query and added the layer use the following code to zoom to the features. Dim pFeatSelection As IFeatureSelection Set pFeatSelection = pFLayer pFeatSelection.SelectFeatures Nothing, esriSelectionResultNew, False 'zoom to all filtered features Dim pEnumGeom As IEnumGeometry Dim pEnumGeomBind As IEnumGeometryBind Set pEnumGeom = New EnumFeatureGeometry Set pEnumGeomBind = pEnumGeom pEnumGeomBind.BindGeometrySource Nothing, pSelectionSet Dim pGeomFactory As IGeometryFactory Set pGeomFactory = New GeometryEnvironment Dim pGeom As IGeometry Set pGeom = pGeomFactory.CreateGeometryFromEnumerator(pEnumGeom) 'update the extent of the map to match the extent of the selected features pAV.Extent = pGeom.Envelope pMXDoc.FocusMap.ClearSelection pAV.Refresh End Sub
Hi Richard,
Thank you very much for the code. I have implemented it, and I reckon this selection method is slightly faster than the merging extent by looping through each features. However when it comes to large number of features, the time taken is still quite significant - users have to click on a button and wait for half a minute before map starts drawing.
I found it is very fast if I right click on the layer in ArcMap and then click "Zoom to Layer" button. Any idea how that function works? I want the application not only work but also work fast (at least time of response is reasonable). Any solution to improve the speed of zooming to the layer with definition query on?
Your suggestion is highly appreciated.
Cheers,
Dim pFCursor As IFeatureCursor pSelSet.Search Nothing, False, pFCursor Dim pEnv As IEnvelope Dim pBigEnv As IEnvelope Set pBigEnv = New Envelope Dim pFeature As IFeature Set pFeature = pFCursor.NextFeature Do Until pFeature Is Nothing Set pEnv = pFeature.Shape.Envelope pBigEnv.Union pEnv Set pFeature = pFCursor.NextFeature Loop pMxDoc.ActiveView.Extent = pBigEnv
'Select features in ArcMap. Dim pFSel As IFeatureSelection Set pFSel = pFLayer ' Assume Definition query is already applied. pFSel.SelectFeatures Nothing, esriSelectionResultNew, False pDoc.ActiveView.Refresh 'Use the Built in Zoom Command to Zoom to the Selected Features Dim pItem As ICommandItem With Project.ThisDocument.CommandBars Set pItem = .Find(arcid.Query_ZoomToSelected) End With pItem.Execute
Dim pUID As New UID Dim pCmdItem As ICommandItem ' Use the CLSID of the Zoom to Selected Features command pUID.Value = "{AB073B49-DE5E-11D1-AA80-00C04FA37860}" pCmdItem = CommandBars.Find(pUID) pCmdItem.Execute
Hi Richard,
It turns out we figured out a different way. As I mentioned before, we have X,Y coordinates value of the points table. So I used SQL query to get min and max X, Y values from the selected points, and created a envelope with these coordinates. The map will be zoom to the envelope instead. It works quite fast, because running SQL takes very minimal amount of time. However, this method is only applicable for our particular exercise, for zooming to a layer with definition query I guess it is a still tough question.
Many thanks for your help! All the suggestions and code are very helpful!