I am trying to make shapefiles with point geometries using GDAL. I am following the example given here. I am using Microsoft Visual Studio and the programming language is C#. For now, I am just making one point at the origin and I'm viewing the resulting shapefiles in QGIS. For some reason, I am not being able to view the point which I make. I have tried making a polygon too but I am facing the same problem. Below is the code I have written:
public void testSF(Dataset ds)
{
Console.WriteLine("Writing ERSI shapefile");
// Registering drivers
OSGeo.OGR.Ogr.RegisterAll();
OSGeo.OGR.Driver driverSH = OSGeo.OGR.Ogr.GetDriverByName("ESRI Shapefile");
if (driverSH == null)
{
Console.WriteLine("Cannot get drivers. Exiting");
System.Environment.Exit(-1);
}
Console.WriteLine("Drivers fetched");
// Creating a shapefile
OSGeo.OGR.DataSource dataSourceSH = driverSH.CreateDataSource("ERSI_TEST_ShapeFile.shp", new string[] { });
if (dataSourceSH == null)
{
Console.WriteLine("Cannot create datasource");
System.Environment.Exit(-1);
}
Console.WriteLine("Shapefile created");
// Creating a point layer
OSGeo.OGR.Layer layerSH;
layerSH = dataSourceSH.CreateLayer("PolygonLayer", null, OSGeo.OGR.wkbGeometryType.wkbPoint, new string[] { });
if (layerSH == null)
{
Console.WriteLine("Layer creation failed, exiting...");
System.Environment.Exit(-1);
}
Console.WriteLine("Polygon Layer created");
// Creating and adding attribute fields to layer
OSGeo.OGR.FieldDefn fdefnName = new OSGeo.OGR.FieldDefn("Name", OSGeo.OGR.FieldType.OFTString);
fdefnName.SetWidth(32);
OSGeo.OGR.FieldDefn fdefnGPS = new OSGeo.OGR.FieldDefn("GPS", OSGeo.OGR.FieldType.OFTString);
fdefnGPS.SetWidth(32);
if (layerSH.CreateField(fdefnName, 1) != 0)
{
Console.WriteLine("Creating Name field failed");
System.Environment.Exit(-1);
}
if (layerSH.CreateField(fdefnGPS, 1) != 0)
{
Console.WriteLine("Creating GPS field failed");
System.Environment.Exit(-1);
}
Console.WriteLine("Fields created and added to layer");
OSGeo.OGR.Feature featureSH = new OSGeo.OGR.Feature(layerSH.GetLayerDefn());
featureSH.SetField("Name", "This is a NAME");
featureSH.SetField("GPS", "Test GPS point");
// Outer Ring
// Methodology: Create a linear ring geometry, add it to a polygon geometry. Add polygon geometry to feature. Add feature to layer
OSGeo.OGR.Feature feature = new OSGeo.OGR.Feature( layerSH.GetLayerDefn() );
OSGeo.OGR.Geometry geom = OSGeo.OGR.Geometry.CreateFromWkt("POINT(0.0 0.0)");
feature.SetGeometry(geom);
layerSH.CreateFeature(feature);
}
This code adds a point to the polygon layer at 0.0 and 0.0. However, when I open the resulting layer in QGIS, I can not see/locate the point. Any help would be appreciated.
I have tested your code with last GDAL release and it works.
You have to close the datasource (call Dispose method) to update the file with the created geometry otherwise you will just view an empty file.
I think You are missing to define the spatial reference
Related
I'm working from the docs on trying to create a sheet with a view on it using the Revit API in C#
here is the docs URL link. You can find the code at the bottom in the first C# block.
I get a red squiggly under the view3D.Id:
Viewport.Create(doc, viewSheet.Id, view3D.Id, new XYZ(location.U, location.V, 0));
I can't find that it was deprecated nor can I figure out how to resolve it. I'm a bit confused about why it's trying to grab its own elementID. Also, just getting into the revit-API. it seems like "views" in Revit are called "viewports" in the API. i need to read more on this.
here is the entire code block:
private void CreateSheetView(Autodesk.Revit.DB.Document document, View3D view3D)
{
// Get an available title block from document
FilteredElementCollector collector = new FilteredElementCollector(document);
collector.OfClass(typeof(FamilySymbol));
collector.OfCategory(BuiltInCategory.OST_TitleBlocks);
FamilySymbol fs = collector.FirstElement() as FamilySymbol;
if (fs != null)
{
using (Transaction t = new Transaction(document, "Create a new ViewSheet"))
{
t.Start();
try
{
// Create a sheet view
ViewSheet viewSheet = ViewSheet.Create(document, fs.Id);
if (null == viewSheet)
{
throw new Exception("Failed to create new ViewSheet.");
}
// Add passed in view onto the center of the sheet
UV location = new UV((viewSheet.Outline.Max.U - viewSheet.Outline.Min.U) / 2,
(viewSheet.Outline.Max.V - viewSheet.Outline.Min.V) / 2);
//viewSheet.AddView(view3D, location);
Viewport.Create(document, viewSheet.Id, view3D.Id, new XYZ(location.U, location.V, 0));
^ERROR HAPPENS IN LINE ABOVE AT view3D.Id
// Print the sheet out
if (viewSheet.CanBePrinted)
{
TaskDialog taskDialog = new TaskDialog("Revit");
taskDialog.MainContent = "Print the sheet?";
TaskDialogCommonButtons buttons = TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No;
taskDialog.CommonButtons = buttons;
TaskDialogResult result = taskDialog.Show();
if (result == TaskDialogResult.Yes)
{
viewSheet.Print();
}
}
t.Commit();
}
catch
{
t.RollBack();
}
}
}
}
The Building Coder discussion of exact viewport positioning includes some woking sample calls to ViewSheet.Create and Viewport.Create.
Have a requirement to add/remove from a CAD drawing using the .NET API an item drawn as an individual CAD entity in the Title Block area which is not an attribute. Is there any way using point references on a CAD drawing or any other method that this could be done through the API?
The CAD entity been asked to remove has an image, client address and web address.
Use this for accessing attributes
BlockTableRecord blkTblRecTitle =
transaction.GetObject(blockTable[BlockTableRecord.PaperSpace],
OpenMode.ForWrite) as BlockTableRecord;
foreach (ObjectId id in blkTblRecTitle)
{
DBObject obj = transaction.GetObject(id, OpenMode.ForWrite);
BlockReference blkRef = obj as BlockReference;
if (blkRef != null)
{
AttributeCollection attCol = blkRef.AttributeCollection;
foreach (ObjectId objID in attCol)
{
DBObject dbObj = transaction.GetObject(objID,
OpenMode.ForWrite) as DBObject;
AttributeReference acAttRef = dbObj as
AttributeReference;
}
}
}
Have managed to find how to add multi line text at a location
using (MText acText = new MText())
{
acText.Location = new Point3d(802, 106.5, 0);
acText.TextHeight = 2;
acText.Contents = "Hello World.\nNow need to right align text.";
blkTblRecTitle.AppendEntity(acText);
transaction.AddNewlyCreatedDBObject(acText, true);
}
Ideally would like to right align but can't see anywhere how I do this with MText which have to use for multiple lines.
Given problems adding text to Paper Space can't see how ever be able to add an image.
To edit .DWG files you need AutoCAD engine, which can be:
desktop: using the existing AutoCAD on your machine, create a .NET/VBA/LISP/C++ plugin that will open, read, modify and save the file. Here is a .NET tutorial.
cloud: using Forge Design Automation webservice to run custom commands/routines with your files. Check the documentation.
Then I would suggest reviewing the blogs here and here for sample codes.
I have an mxd file that I've loaded into ArcMap. When finished loading, there are several layers; some of which that have multiple feature classes. The end result is listing all the filepaths/locations/source of each feature class, but for now, I just need to know how to list all the feature classes that are loaded. And when I say list, they can really just be output to the screen via message boxes. I know I'll need to loop through each layer, but utilizing the right interface and accessing ArcMaps properties is where I get lost.
Any help on this would be greatly appreciated. I'm still learning ArcObjects and how it all works and in desperate need of help. Thanks in advance.
This would be an example in C# to loop through all layers and if it's a feature layer, get until the workspace to get the path or whatever from it:
/* Make a list of all feature classes. */
List<ILayer> layers_list = new List<ILayer>();
IMap map = get_map();
IEnumLayer enumLayer = map.get_Layers(null, true);
ILayer layer = null;
while (layer = enumLayer.Next() != null) {
// we're looking for a feature class only
if (layer is IFeatureLayer) {
try {
IFeatureClass fclass = ((IFeatureLayer)layer).FeatureClass;
IFeatureLayer featureLayer = (IFeatureLayer)layer;
// Get the dataset and workspace of the feature class
IDataset ds = (IDataset)fclass;
IWorkspace ws = (IWorkspace)ds.Workspace;
// Do something with the workspace, like getting the path or
// whatever...
} catch (Exception e) {
MessageBox.Show("Layer ' " + layer.Name + "': \n\n" + e.Message);
}
}
}
I am working on a Task in which the code automatically opens a drawing selected by the user [in a UI] and selects all the objects in the drawing and starts to explode all the of them till they cant be exploded anymore. While doing this I face a problem, the original (un-exploded 3D object) is still present in the drawing, super imposed by the Exploded object. Every recursive call of the Explode function creates a new exploded 3D object of that object.
Here is a snippet of the code I working on:
PromptSelectionResult ss = ed.SelectAll();
using (DocumentLock acLckDoc = doc.LockDocument())
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
objs = new DBObjectCollection();
foreach (SelectedObject so in ss.Value)
{
Entity ent = (Entity)tr.GetObject(so.ObjectId, OpenMode.ForWrite);
if (!(ent is Solid3d))
{
ent.Explode(objs);
ent.UpgradeOpen();
ent.Erase();
}
}
tr.Commit();
}
}
As soon as the control comes on to the ent.Erase() statement - it throws an exception, eCannotBeErasedByCaller. I cant figure out why? I have unlocked all layers, opened the entity for Write, CommandFlags have been set to Session and UsePickSet (shuffled through all).
Anybody got any suggestions?
Looking at your description, you probably need a recursive explode. Sometime ago I did a code around this, for other type of entities, but you can adjust it.
private List<DBObject> FullExplode(Entity ent)
{
// final result
List<DBObject> fullList = new List<DBObject>();
// explode the entity
DBObjectCollection explodedObjects = new DBObjectCollection();
ent.Explode(explodedObjects);
foreach (Entity explodedObj in explodedObjects)
{
// if the exploded entity is a blockref or mtext
// then explode again
if (explodedObj.GetType() == typeof(BlockReference) ||
explodedObj.GetType() == typeof(MText))
{
fullList.AddRange(FullExplode(explodedObj));
}
else
fullList.Add(explodedObj);
}
return fullList;
}
source: http://adndevblog.typepad.com/infrastructure/2013/04/get-cogopoint-label-text.html
I finally found out the reason why the Original objects werent getting erased.
In the earlier part of the code, a AutoCAD Plant3D dwg is exported to AutoCAD (ExporttoAutoCAD / Saveas), this was creating Proxy items. These cant be deleted manually or via code.
Only way is to explode the PipeLines and Inline assets before exporting the file. This happens automatically if you export the file, but if you use saveas, you will have to explode the Pipe components before you export the file.
Wasted a lot of time understanding the cause, but finally got it!
I'm trying to create a standalone application, which loads a ArcGis map, selects a few objects in one layer and zooms to them.
Loading and displaying the map does work, using something like this:
AxMapControl _mapControl;
// in constructor:
_mapControl = new AxMapControl();
// in loading
_mapControl.LoadMxFile(#"C:\Users\me\Documents\TestProject.mxd");
This does work nicely and does display the map as full extent (of course the AxMapControl is embedded into a WindowsFormsHost, but this shouldn't be a problem).
But now I need to select one or more objects and zoom to them. I tried to select in one layer for testing, but this does not work at all:
IFeatureSelection features = _mapControl.Map.Layer[0] as IFeatureSelection;
if (features != null)
{
QueryFilter qf = new QueryFilterClass();
qf.WhereClause = "[Name]='FS4711000'";
features.SelectFeatures(qf, esriSelectionResultEnum.esriSelectionResultNew, false);
}
on the SelectFeatures call I get an COM error 80004005 (E_Fail) in ESRI.ArcGIS.Carto, without much more explanation. Probably I'm doing it all wrong.
Maybe someone has a sample how to select objects in a layer?
I think your issue is as simple as the [square brackets] around your field name in the query string.
This works:
IFeatureSelection features = _currentLayer as IFeatureSelection;
if (features != null)
{
QueryFilter qf = new QueryFilter();
qf.WhereClause = "Type='1'";
features.SelectFeatures(qf, esriSelectionResultEnum.esriSelectionResultNew, false);
}
_axMapControl.Refresh();
Whereas this fails with COM-error E_FAIL:
IFeatureSelection features = _currentLayer as IFeatureSelection;
if (features != null)
{
QueryFilter qf = new QueryFilter();
qf.WhereClause = "[Type]='1'";
features.SelectFeatures(qf, esriSelectionResultEnum.esriSelectionResultNew, false);
}
_axMapControl.Refresh();
Also, notice that the map (or at least the IActiveView returned by AxMapControl.ActiveView) needs to be manually refreshed, or the selection is not displayed before the map is redrawn.