How to export WKT from a Shapefile in c#? - c#

I have a Shapefile that contains several thousand polygons.
I need to read from this file in C# and output a list of WKT formatted strings.
I looked at DotSpatial and the "CatFood" ESRI Shapefile Reader. I can get either to load the shapefile just fine, but I cannot figure out how to then export as WKT.
In DotSpatial, the only examples I could find use a WktWriter which takes a Geometry. I couldn't figure out how to get a Geometry from a Shape.
Is there a library that's more appropriate for this?
Update
Thanks to mdm20's answer, I was able to write the following:
using (var fs = FeatureSet.Open(path))
{
var writer = new WktWriter();
var numRows = fs.NumRows();
for (int i = 0; i < numRows; i++)
{
var shape = fs.GetShape(i, true);
var geometry = shape.ToGeometry();
var wkt = writer.Write((Geometry) geometry);
Debug.WriteLine(wkt);
}
}
The reason I missed it originally is because I was following this sample, which uses fs.ShapeIndices instead of fs.GetShape(). That returns not a Shape, but a ShapeRange, which I couldn't convert to a geometry.
New Questions
Should I be setting fs.IndexMode = true? Why or why not? It doesn't seem to have any performance or results impact.
fs.GetShape() takes a boolean called getAttributes. I do have attributes on my shapes, and they seem to come through whether this is set true or false. Again, there is no noticeable performance impact either way. Is that expected?
By getting them in this way, does the WKT represent the actual values stored in the shapefile? Or are they transformed in any way? Is it taking any default settings from dotSpatial into account, and should I be concerned about changing them?
The shapefile I am importing is the world timezone map. It does contain a .prj file. Does dotSpatial take this into account, and if not - do I need to do anything extra?
Many Thanks!

In DotSpatial, the Shape class has a ToGeometry method.
/// <summary>
/// Converts this shape into a Geometry using the default factory.
/// </summary>
/// <returns>The geometry version of this shape.</returns>
public IGeometry ToGeometry()
{
return ToGeometry(Geometry.DefaultFactory);
}
Edit
I've only used the dotspatial stuff for projections, so I can't really help you too much.
1-2: Not sure. The code is open source if you want to look and see what they do
3: WKT is a human readable text representation of the geometry. I would assume that it's the same value as the file, but I don't know. Again.. check out the dotspatial source code
4: The prj file tells you what projection the geometry is in. Depending on what you want to do with it, you might have to re-project it. Things like Bing Maps and Google Earth use a mercator projection, for instance. The dotspatial projections library is good and makes it easy to transform the geometry from one projection to another.
I've done quite a bit of work with shapefiles.. let me know if you have more questions.

try this:
private void button1_Click(object sender, EventArgs e)
{
String result = "";
OpenFileDialog openfile = new OpenFileDialog();
openfile.Filter = "Shapefile (*.shp)|*.shp|All files (*.*)|*.*";
openfile.ShowDialog();
String filePath = openfile.FileName.Replace(".shp", "").Replace(#"\", #"\\");
String[] a = filePath.Split('\\');
String shpName = a[a.Length-1];
try
{
SQLiteConnection.CreateFile(openfile.FileName.Replace(".shp", "")+".sqlite");
System.Data.SQLite.SQLiteConnection connection = new SQLiteConnection(#"Data Source=" + openfile.FileName.Replace(".shp", "") + ".sqlite");
connection.Open();
object returnvalue = new SQLiteCommand("SELECT load_extension('libspatialite-2.dll')", connection).ExecuteScalar();
System.Data.SQLite.SQLiteCommand commande = new SQLiteCommand(connection);
commande.CommandText = "CREATE virtual TABLE "+shpName+"VT USING VirtualShape('" + filePath + "', 'CP1252', 4326);";
commande.ExecuteScalar();
commande.CommandText = "CREATE TABLE geom AS SELECT * FROM " + shpName + "VT;";
commande.ExecuteScalar();
commande.CommandText = "drop table " + shpName + "VT";
commande.ExecuteScalar();
commande.CommandText = "ALTER TABLE geom ADD COLUMN WKT TEXT;";
commande.ExecuteScalar();
commande.CommandText = " UPDATE geom set WKT= ST_AsText(Geometry);";
commande.ExecuteScalar();
// the test commande
commande.CommandText = "SELECT WKT FROM geom;";
result = (string)commande.ExecuteScalar();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
MessageBox.Show(result);
}

First open the shapefile and then get its features basic geometry.......
IFeatureSet fb = FeatureSet.Open("F:\\Test_value\\test.shp");
List<string> str = new List<string>();
foreach (IFeature ff in fb.Features)
{
Geometry geometry = ff.BasicGeometry as Geometry;
WktWriter wktWriter = new WktWriter();
str.Add(wktWriter.Write(geometry));
}

Related

Parsing RDF - dotnetrdf c#

This is my first time ever looking at RDF, and after trying, I've no idea how to parse it. I'm looking at some RDF (in Turtle format) used in the AFF4 file system, here's a portion of it:
<aff4://0295fab8-94b7-4435-bdb3-932cf48e40bd>
a aff4:ImageStream ;
aff4:chunkSize "32768"^^xsd:int ;
aff4:chunksInSegment "2048"^^xsd:int ;
aff4:compressionMethod <http://code.google.com/p/snappy/> ;
aff4:imageStreamHash "82798a275176aa141a2993ca8931535b1303545a0954473f5c5e55b4d8d5a8e3ebdb9e9323e5ecfaf65f8d379a8e2b9150750f5cf44851cf4edb6a2e05372f42"^^aff4:SHA512 ;
aff4:imageStreamIndexHash "039eb2da046cfb8c8d40e6f9b42aae501fb36f9b09b5f29d660d3637f87c37c98c3ee3b995265adff1d2b971fa795317333bf50200e72fdfe9fa96acdb88b6d0"^^aff4:SHA512 ;
aff4:size "185335808"^^xsd:long ;
aff4:stored : ;
aff4:target <aff4://92015053-5f7b-4e5a-a1e7-901d8943cf1f> ;
aff4:version "1"^^xsd:int .
There's a lot of this stuff in the file, but I've no idea how to access any of it, thus far I've cobbled together:
private static void ParseInformationStream(Stream informationStream)
{
Console.WriteLine("Parsing information.turtle file: ");
informationStream.Position = 0;
TurtleParser turtleParser = new TurtleParser();
Graph graph = new Graph();
turtleParser.Load(graph, new StreamReader(informationStream));
foreach (var triple in graph.Triples)
{
Console.WriteLine(triple.Subject);
}
}
This prints out some of the data, but if for example, I wanted to access the aff4:compressionMethod (node?) specifically, how would I go about doing that? I've been reading about Sparql, but it all seems a bit overkill for what I need.
Any input or advice would be appreciated.
You can use the methods of the IGraph interface to access the contents of the parsed graph. For example the following will retrieve all image streams (in Turtle "a" is a shortcut for the rdf:type predicate) and print out the compression method for each stream:
// Get the node for rdf:type
var rdfType = graph.CreateUriNode(new Uri(RdfSpecsHelper.RdfType));
// Get the node for the aff4:ImageStream type
var imageStream = graph.GetUriNode("aff4:ImageStream");
// Get the node for the aff4:compressionMethod predicate
var compressionMethod = graph.CreateUriNode("aff4:compressionMethod");
// Get the streams (the subject of x a aff4:ImageStream in the Turtle)
var imageStreams = graph.GetTriplesWithPredicateObject(rdfType, imageStream).Select(t => t.Subject);
foreach (var streamInstance in imageStreams)
{
// Get the first compressionMethod value for the stream instance
var compression = graph.GetTriplesWithSubjectPredicate(streamInstance, compressionMethod)
.Select(t => t.Object).FirstOrDefault();
Console.WriteLine("Stream " + streamInstance + " uses compression method " + compression);
}
For more on accessing nodes an triples in a graph in dotNetRDF, please see https://github.com/dotnetrdf/dotnetrdf/wiki/UserGuide-Working-With-Graphs

How to get the slidetype (type-attribute) of a slidelayout-slide?

Application is a C# based VSTO-AddIn for PowerPoint.
Each SlideLayout in powerpoint has a type. Is there way to get the type in an VSTO-AddIn? Up to now I just know how to get it from the SlideLayout.xml
Yes, the PowerPoint object model exposes an enumeration PpSlideLayout so something like
PowerPoint.PpSlideLayout theLayout = theSlide.Layout;
Here's a code snippet that creates a new slide (which requires assigning a CustomLayout), shows the string values of the custom layout and the PpSlideLayout, then assigns a different PpSlideLayout
PowerPoint.Presentation p = this.Application.ActivePresentation;
PowerPoint.PpSlideLayout layoutBlank = PowerPoint.PpSlideLayout.ppLayoutBlank;
PowerPoint.CustomLayout custLayout = p.SlideMaster.CustomLayouts[1];
PowerPoint.Slide s = p.Slides.AddSlide(2, custLayout);
System.Windows.Forms.MessageBox.Show(s.CustomLayout.Name + ", " + s.Layout.ToString());
s.Layout = layoutBlank;

Copy/Clone an Excel Chart with EPPlus

I'm using EPPlus in my project and I know you can copy an existing Shape however there is no method for copying an existing Chart.
I have setup a workbook with template charts that I need to duplicate and update the series to point to different datatable/sets.
I can populate the data no worries and can create new charts, but then need to size and position and style. It would be a lot easier to just clone the chart template and modify series and position to simplify the code.
Currently I use this approach:
// wb is an ExcelWorkbook
ExcelWorksheet ws = wb.Worksheets[sheetIdx];
ExcelChart chart = (ExcelChart)ws.Drawings[0];
ExcelChart cc = ws.Drawings.AddChart("Chart " + (i + 2), eChartType.ColumnClustered);
// invoke methods that will position and size new chart
// copy starting chart xml so will have identical styling, series, legend etc
var xml = XDocument.Parse(chart.ChartXml.InnerXml);
XNamespace nsC = "http://schemas.openxmlformats.org/drawingml/2006/chart";
XNamespace nsA = "http://schemas.openxmlformats.org/drawingml/2006/main";
// modify xml to update Category, Title and Values formulas
var fs = xml.Descendants(nsC + "f");
foreach (var f in fs)
{
f.Value = ws.Cells[f.Value].Offset(chartNumRows + 1, 0).FullAddressAbsolute;
}
// set new chart xml to modified xml.
cc.ChartXml.InnerXml = xml.ToString();
Which works, but there are several drawbacks.
1) The chart.series of the clone (cc in my example) has not been set, peeking at the code this is because it is only done during the object construction. If I could get this property to update then I would be able to easily resolve the second issue
2) I need to remove all series and add new ones and because the series property isn't initialised properly this is harder than it should be.
Any help getting properties to initialise in the chart or a better method of cloning the original would be greatly appreciated!
It seems like there is no built-in functionality for this and an other reload methods I could come up with required too many changes to the EPPlus source, so until I find a better solution I have added the following method to EPPlus\Drawings\ExcelDrawings.cs
public ExcelChart CloneChart(ExcelChart SourceChart, String NewName)
{
// Create clone
var tempClone = this.AddChart(NewName, SourceChart.ChartType, null);
tempClone.ChartXml.InnerXml = SourceChart.ChartXml.InnerXml;
// Reload clone
using (tempClone.Part.Stream = new MemoryStream())
{
// Create chart object using temps package and xml
var chartXmlBytes = Encoding.ASCII.GetBytes(tempClone.ChartXml.OuterXml);
tempClone.Part.Stream.Write(chartXmlBytes, 0, chartXmlBytes.Length);
var finalClone = ExcelChart.GetChart(this, tempClone.TopNode);
// Remove old from collection
var index = _drawingNames[tempClone.Name];
var draw = _drawings[index];
for (int i = index + 1; i < _drawings.Count; i++)
_drawingNames[_drawings[i].Name]--;
_drawingNames.Remove(draw.Name);
_drawings.Remove(draw);
// Add new to collection
finalClone.Name = tempClone.Name;
_drawings.Add(finalClone);
_drawingNames.Add(finalClone.Name, _drawings.Count - 1);
// Done
return finalClone;
}
}

while loop execution with Tupled List c#

I have this code for insertion of data into database. I have created a tupled List of <string, double, string[]> and add elements to List inside a nested while loop. Here is the code....
System.IO.StreamReader file = new System.IO.StreamReader(#"C:\Users\Malik\Desktop\research_fields.txt");
Program p = new Program();
var dd = new List<Tuple<string, double, string>>();
//string document = "The trie data structure has many properties which make it especially attractive for representing large files of data. These properties include fast retrieval time, quick unsuccessful search determination, and finding the longest match to a given identifier. The main drawback is the space requirement. In this paper the concept of trie compaction is formalized. An exact algorithm for optimal trie compaction and three algorithms for approximate trie compaction are given, and an analysis of the three algorithms is done. The analysis indicate that for actual tries, reductions of around 70 percent in the space required by the uncompacted trie can be expected. The quality of the compaction is shown to be insensitive to the number of nodes, while a more relevant parameter is the alphabet size of the key.";
//string[] document = get_Abstract();
string line;
try
{
SqlConnection con = new SqlConnection("Data Source=KHIZER;Initial Catalog=subset_aminer;Integrated Security=True");
con.Open();
SqlCommand query = con.CreateCommand();
query.CommandText = "select p_abstract from sub_aminer_paper where pid between 1 and 500 and DATALENGTH(p_abstract) != 0";
SqlDataReader reader = query.ExecuteReader();
string summary = null;
while (reader.Read())
{
summary = reader["p_abstract"].ToString();
while ((line = file.ReadLine()) != null)
{
dd.Add(Tuple.Create(line, p.calculate_CS(line, summary), summary));
}
var top_value = dd.OrderByDescending(x => x.Item2).FirstOrDefault();
if (top_value != null)
{
// look up record using top_value.Item3, and then store top_value.Item1
var abstrct = top_value.Item3.ToString();
var r_field = top_value.Item1.ToString();
write_To_Database(abstrct, r_field);
}
}
reader.Close();
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
finally
{
Console.WriteLine("Executing finally block.");
}
I have debugged it in visual studio 2013 using c#, I have seen the statement that is inside the inner while loop i.e. dd.Add(Tuple.Create(line, p.calculate_CS(line, summary), summary)); executes only once while it should be executes 22 times as reader.Read() has a length 22 documents.
I have checked it by taking only single string document shown as //comment in code and it works fine but not with reading documents from database.
Not getting why is it so. Any suggestions will be highly appreciated.
To get inside while loop, your line = file.ReadLine()) != null should be true. If you only get there once, I suspect you have only one line in your file, therefore, no matter how many elements your document array has, code inside while will execute only once.
Overall, however, your while loop code doesn't make much sense to me. You are going to read all you text from the file in your first iteration of for and then while loop will be skipped forever. If it's your intention to read all lines exactly once, move while before the for.
To further improve your code look up ReadLines and AddRange pages.
And to find a max value in the colleciton instead of
var top_value = dd.OrderByDescending(x => x.Item2).FirstOrDefault();
use Max:
var top_value = dd.Max(x => x.Item2);
Update:
var lines = System.IO.File.ReadLines(#"C:\Users\Malik\Desktop\research_fields.txt");
while (reader.Read())
{
summary = reader["p_abstract"].ToString();
dd.AddRange(lines
.Select( line =>
Tuple.Create(line, p.calculate_CS(line, summary), summary)
)
);
// rest of your stuff
}

Get all measures associated with given measure group

Im writing c# application using Microsoft.AnalysisServices in which I would like to retreive MeasureGroups measures from my Cube.
Here is the code:
Server server = new Server();
server.Connect(serverName);
Database database = server.Databases.FindByName(databaseName);
Cube cube = database.Cubes.FindByName(cubeName);
Here I have my Cube and then:
MeasureGroup sampleMeasureGroup = cube.MeasureGroups[0];
Then I can get measures associated with sampleMeasureGroup by simply:
var measures = sampleMeasureGroup.Measures;
But in this case I dont get Calculated measures, only standard ones. Is there any way I can get calculated measures ?
You can use the low level API which accesses the schema rowsets like this:
AdomdClient.AdomdRestrictionCollection restrColl = new AdomdClient.AdomdRestrictionCollection();
restrColl.Add("CUBE_NAME", cube.Name);
DataSet ds = clientConn.GetSchemaDataSet("MDSCHEMA_MEASURES", restrColl);
foreach(DataRow row in ds.Tables[0].Rows) {
string expr = row.Field<string>("EXPRESSION");
if (string.IsNullOrEmpty(expr)) {
// measure is a physical measure
} else {
// measure is a calculated measure, and 'expr' is its definition
}
// use other columns like MEASURE_NAME, MEASURE_UNIQUE_NAME, DATA_TYPE,
// DEFAULT_FORMAT_STRING ... as you need them
}
The MDSCHEMA_MEASURES rowset lists all measures contained in the cube, and is documented here: http://technet.microsoft.com/en-us/library/ms126250.aspx

Categories

Resources