Programatic way to do linear referencing in ArcGIS - c#

I am working on a custom ArcGIS Desktop tool project and I would like to implement an automated linear referencing feature in it. To make a long story short, I would like to display problematic segments along a route and show the severity by using a color code (say green, yellow, red, etc.). I know this is a pretty common scenario and have come to understand that the "right way" of accomplishing this task is to create a linear event table which will allow me to assign different codes to certain route segments. Some of my colleagues know how to do it manually but I can't seem to find any way to replicate this programaticaly.
The current tool is written in C# and already performs all the needed calculations to determine the problematic areas. The problem mainly is that I don't know where to start since I don't know a lot about ArcObjects. Any code sample or suggestion is welcome (C# is preferred but C++, VB and others will surely help me anyway).
EDIT :
I'm trying to use the MakeRouteEventLayer tool but can't seem to get the different pre-conditions met. The routes are hosted on an SDE server. So far, I am establishing a connection this way :
ESRI.ArcGIS.esriSystem.IPropertySet pConnectionProperties = new ESRI.ArcGIS.esriSystem.PropertySet();
ESRI.ArcGIS.Geodatabase.IWorkspaceFactory pWorkspaceFactory;
ESRI.ArcGIS.Geodatabase.IWorkspace pWorkspace;
ESRI.ArcGIS.Location.ILocatorManager pLocatorManager;
ESRI.ArcGIS.Location.IDatabaseLocatorWorkspace pDatabaseLocatorWorkspace;
pConnectionProperties.SetProperty("server", "xxxx");
pConnectionProperties.SetProperty("instance", "yyyy");
pConnectionProperties.SetProperty("database", "zzzz");
pConnectionProperties.SetProperty("AUTHENTICATION_MODE", "OSA");
pConnectionProperties.SetProperty("version", "dbo.DEFAULT");
pWorkspaceFactory = new ESRI.ArcGIS.DataSourcesGDB.SdeWorkspaceFactory();
pWorkspace = pWorkspaceFactory.Open(pConnectionProperties, 0);
pLocatorManager = new ESRI.ArcGIS.Location.LocatorManager();
pDatabaseLocatorWorkspace = (ESRI.ArcGIS.Location.IDatabaseLocatorWorkspace)pLocatorManager.GetLocatorWorkspace(pWorkspace);
Now I am stuck trying to prepare everything for MakeRouteEventLayer's constructor. I can't seem to find how i'm supposed to get the Feature Layer to pass as the Input Route Features. Also, I don't understand how to create an event table properly. I can't seem to find any exemple relating to what I am trying to accomplish aside from this one which I don't understand since it isn't documented/commented and the datatypes are not mentionned.

I'm not entirely certain what it is you want to do. If you want to get Linear Referencing values or manipulate them directly in a feature class that already has linear referencing defined, that's pretty straight forward.
IFeatureClass fc = ....;
IFeature feature = fc.GetFeature(...);
IMSegmentation3 seg = (IMSegmentation3)feature;
... blah ...
If you need to create a Feature class with linear referencing, you should start witht he "Geoprocessing" tools in the ArcToolbox. If the out-of-the-box tools can do most of what you need, this will minimize your coding.
I would strongly recommend trying to figure what you need to do with ArcMap if at all possible... then backing out the ArcObjects.
Linear Referencing API
Linear Referencing Toolbox
Understanding Linear Referencing

Related

Templated Lists in C#?

I know templates are common within c/c++ however I am currently trying to translate an old VB code our company uses up to a c# equivalent which brings me to my problem....
VB is an type unsafe language so we come across things like
Public Elements As New Collection
so given the line above I need to translate that to a List.. Given that a Collection can be anything from a List to a map I need to template this as efficiently as possible. I was thinking of for first draft ignoring the map option entirely and just making it a List however from my understanding Templates don't truly exist within C#... The below code is what I came up with so far and while it compiles (I have not gotten to a testing point in the rest of the code yet) I don't know if it would actually work...
Public List<ValueType> Elements = new List<ValueType>();
can anyone offer input on if this would work as a generic list where type is determined at input or if I need to change this so the constructor would look more like
Public List<ValueType> Elements = new List<typeof(foo)>();
if the above is confusing I am sorry it is for me as well, and I will try and clarify as questions come in.
this question is no longer relevant, I was able to go into the source of the calling code and determine what variable types that the lists need to support.

Fill object from SQL result

I have a regular C# class called "vehicle" with properties like Name, NumberPlate, MaxSpeed, etc.
All the data for the class is stored in a SQLite Database where I have a Table "Car" and "Boat". The tables colums have the same names as the class properties (however, there are more columns than class properties - vehicle is a more generic abstraction). At the moment, I have to assign the result of the query individually one by one like this:
while (await statement.StepAsync())
{
myVehicle.Name = statement.Columns["Name"];
//[...]
myVehicle.MaxSpeed = decimal.TryParse(statement.Columns["MaxSpeed"]);
}
Additionally, I have to check if some columns exist ("Car" and "Boat" have a different set of columns) which is more code than I'd like it to be.
I read about EntityFramework to map my db table to my class - but that seems overkill. My requirement is to map properties and columns that have the same name and ignore everything else.
Is there a "easy" (dev time, lines of code) way to map my table columns to my class?
Thanks for reading!
The restrictions in phone 8 mean that a lot of the standard answers to this ("just use {some ORM / micro-ORM}") won't apply, since they don't work on phone 8. You can probably use reflection for a lot of this, but: reflection can be (relatively) slow, so it depends on how much data you will be processing. If it is occasional and light: fine, reflect away.
Runtime meta-programming (the tricks used by libraries like "dapper" in full .NET to make these things really fast) is not available on restricted runtimes, so if you want to avoid lots of boiler-plate that leaves build-time meta-programming. At the simplest, I wonder if you could use something like T4 to automate creating these methods for you as C#. There are also ways to use the reflection-emit API to construct assemblies (at build-time) for phone 8, but that is a pretty hard-core route.
My thoughts:
if the amount of types here isn't huge, just write the code
if you have a lot of types, or you just feel like it, consider a build-time code-generation meta-programming step; you might even think "hmm, is this something I could make available to the community?"
of course, the first thing to do is to check that such a thing doesn't already exist
There is a little helper which might fit your case. Basically, it will take a dictionary and try it's best to populate a objects properties using reflection. I didn't try it by myself though.
You'd simply do something like:
while (await statement.StepAsync())
{
myVehicle = DictionaryToObject<Car>(statement.Columns);
}
It might need some further work to get it running but maybe a good start.

Entity Framework 5 Enum that is built from a db table

I have those two entities :
Color entity is mapped to a table of constant values that represent colors.
Code=1, Name="Red"
Code=2, Name="Blue"
And so on...
In Car entity, the Color property is of type int and has a foreign key constraint to the Code property in Color entity. I want to convert the Color property in Car to an Enum, but the Enum should get it's values from Color table.
The Enum could be updated in each build action or an "update model" action in the designer.
Can this functionality can be achieved ?
" but the Enum should get it's values from Color table. "
So whats wrong with what you have? Anyway since you asked...
An enum is by definition inside the assembly. So as soon as a new color is added to the table you have an outdated Enum. But if you are ok with having upto date at build time. There is a good option.
Clearly the suggestion to use T4 is interesting . But the t4 would need to connect to DB and read it. When T4 goes beyond source generation, it can be easier to use a simple app. Unless of course you are already good at t4. So if t4 is a little hard for this task try:
A simple side app, that reads the DB and updates the EnumColor.cs would be plausible.
IE a simple console app. Place as a pre build step. The pre-build reads the DB, rewrites the enum.cs file and the compile/build then follows.
**Easy Alternative: using a Dictionary which you can extend at runtime **
Dictionary<int,string> colors
For me the first question is why? I had a similar technical need but the business need was to help with reporting. Enums works great to make code simpler to read and maintain, but is you have to create a report in say SSRS then you don't have access to the enums (okay I am sure some advanced SSRS users will say you can link in assemblies etc, but that is not the point). We played a bit with a prebuild script (could also run post build) to generate inline scaler function scripts to execute against the db. This way you could do select statements such as:
SELECT Model, fColorNameEnum(Color) FROM Car
This way you do not have to touch you reports again if you add a new element in your enum. I tend to use enums in the implementation of business logic, typically item status or workflow state. Adding a new option thus require adding new logic which means doing it in code. If you are never going to reason over the color value in code, then what is the reason for wanting to put it in an enum rather than just another linked object?

Creating and populating an excel sheet with late-binding

I've been looking at the microsoft support page Binding for Office automation servers with Visual C# .NET to try to create an Excel Worksheet, populate it with values in a datatable, and save it to the machine.
I have an implementation that uses early-binding and simply loops through the items, but I don't know how you would achieve this with late-binding, and I need to be able to embed the Interop types to make the application version independent in regard to MS Office.
How would I add the rows from a datatable to a new Excel Worksheet using late-binding?
I would recommend writing an interface and abstracting the data population step, and the excel step. That way you can have a system that implements early binding with excel to do things, and then an engine that uses this interface to populate the excel sheet. Step 2 would be to write a second implementation of the interface using Late Binding rather than early binding. Then you just substitute the second implementation for the first in your code when you create the interface.
In the code, you would only create 1 object, the interface itself. When creating it though, you can assign it as any other class/implementation that implements that interface...here's an example from my own code:
ISpreadsheetControl SSInterface;
if (conditionCheck())
SSInterface = new ExcelImplementer();
else
SSInterface = new OpenOfficeImplementer();
I Only ever use the 1 object, SSInterface, when placing data or changing page settings, etc etc...whatever else I implemented...but it can do so in two different manners based on which Class I assigned to the interface at load time.
As for the specifics and details on "how to"...I find the second example in the link you provided to be very helpful indeed. Its all about Type and Invoke. The difficulty will be keeping track of what you are working with at any given time. That is one of the things that will make it harder to work with, and a good reason to extract the early binding implementation first. That way you can see all the method names you will need and their parameter lists when writing the second.
I also want to add this: The very simple and short answer to your question is "Do it exactly the same way you already are" You just change 'how' you are calling the method that is populating the data...and all the rest of the excel interop implementation along with it.
UPDATE
I think this might do what you are looking for, although its messy enough that I would recommend putting it (both operations actually, one can call the other) into its own separate method, somewhere.
//Get a range object that contains the cell.
Parameters = new Object[2];
Parameters[0] = iRow + 1;
Parameters[1] = iCol;
objRange_Late = objSheet_Late.GetType().InvokeMember( "Cells",
BindingFlags.GetProperty, null, objSheet_Late, Parameters );
//Write value in cell
Parameters = new Object[1];
Parameters[0] = row[col.ColumnName];
objRange_Late.GetType().InvokeMember( "Value", BindingFlags.SetProperty,
null, objRange_Late, Parameters );
I have to admit, I don't have an implementation that I can test this on right now, but according to the things I know about it, that should work. If "Cells" doesn't work, I would also the same code with "Range"...I dont actually know if that one takes numerical input or not.
link to Cells property description (msdn)
you might also want to explore that whole system a bit, it can help you find some of the things you might be looking for.
Tested Managed to successfully create and test the above code, it works perfectly.

DRY in C# code documentation on two interface variants

I am currently rewriting a SDK to access a webservice.
Since the model for a database query consists of many classes (actually one class for each of about twenty possible filters), I decided to provide a fluent interface additonally.
So instead of
new Query(
Age = new AgeFilter() { From = 18, To = 65 },
Location = new PostalCodeFilter() { Zip = 12345, new RadiusDefinition() { ... } }
);
the user can now write:
Query.Create()
.WithAge(18, 65)
.WithLocation(12345, 50, "miles");
Now I found out that the traditional way has to be included as well (I cannot hide the actual objects as internal).
How can I avoid having to document both the parameters of the fluent interface and the fields of the data classes? The descriptions are the same. I thought about see/seealso but this wouldn't show up in Visual Studio's Code Assistant.
If you use Sandcastle you can use the <inheritdoc /> tag just like this:
///<param name="from">
///<inheritdoc cref="AgeFilter.From" select="/summary/node()" />
///</param>
or
///<summary>
///<inheritdoc cref="QueryFilters.WithAge" select="/param[#name='from']/node()"/>
///</summary>
I don't think you can. An xml-doc comment is applied to a very specific thing and isn't easily "shared". But, you can "link" between elements using the <see> tag. Have a look at http://msdn.microsoft.com/en-us/library/acd0tfbe.aspx and see if it's of use to you.
Understand that DRY really applies mainly to code; writing the same line of code twice means that if a change to the logic inherent in that code has to be made, it has to be made twice. What you're trying to avoid repeating is markup, which while it can have the same inherent problem of having to make changes in multiple places, markup usually has fewer tools available to avoid restating similar things. If you look at other libraries which have multiple ways to accomplish a similar goal, you'll find that a lot of the documentation appears copy-pasted.

Categories

Resources