Showing posts with label Microstation. Show all posts
Showing posts with label Microstation. Show all posts

Monday, August 19, 2013

Simple C# example using SharpMap and OGR to read a DGN file

SharpMap is an easy to use library for working with GIS data. It comes with wrappers for OGR and GDAL. I recently had to work with DGN files. I thought I would share that experience by posting a simple C# wrapper for reading a Microstation DGN file (version 7) as SharpMap geometries.

The example code below simply opens up a DGN file as an OGR data source. The wrapper exposes a public method to return all the DGN elements as SharpMap geometries for further manipulation.



//...etc...
using SharpMap;
using SharpMap.Geometries;
using SharpMap.Converters.WellKnownBinary;
using SharpMap.Converters.WellKnownText;
using OSGeo.OGR;
 
//A simple example DGN file wrapper using SharpMap and OGR
public class DGNFile
{
#region private member variables
//Variable for the OGR DGN data source
private DataSource _dataSource = null;
private ArrayList _layers = new ArrayList();
#endregion
public DGNFile(string filename)
{
//Register OGR drivers
Ogr.RegisterAll();
string format = string.Empty;

//Attempt to open the DGN file with OGR. 
//If successful, the format string "DGN" will be returned. 
//Otherwise, throw an exception
_dataSource = Ogr.Open(filename, 0);
if (_dataSource != null)
{
format = _dataSource.GetDriver().GetName();
}
if (format.CompareTo("DGN") != 0 || _dataSource == null)
{
throw new Exception("Unable to open DGN file");
}
 
//Get a list of the DGN layers. 
//Note: so far, I have not encountered more than 1 layer
for (int i = 0; i < _dataSource.GetLayerCount(); i++)
{
Layer layer = _dataSource.GetLayerByIndex(i);
if (layer != null)
{
FeatureDefn def = layer.GetLayerDefn();
_layers.Add(def.GetName());
}
}
}
//Just a destructor to free up the OGR resources
~DGNFile()
{
if (_dataSource != null)
{
_dataSource.Dispose();
}
}
//A public method to get all the DGN elements as SharpMap geometries
public ArrayList GetElements()
{
ArrayList geometries = new ArrayList();
 
for (int i = 0; i < _layers.Count; i++)
{
string layerName = (string) _layers[i];
Layer layer = _dataSource.GetLayerByName(layerName);
FeatureDefn def = layer.GetLayerDefn();

//A reset is necessary if you want to read the DGN from the top of the file again
layer.ResetReading();
Feature fea;

//Loop through all the elements
while ((fea = layer.GetNextFeature()) != null)
{
OSGeo.OGR.Geometry geom = fea.GetGeometryRef();
if (geom != null)
{
wkbGeometryType geomType = geom.GetGeometryType();
geom.FlattenTo2D();

//Allocate a buffer to store the WKB geometry
Byte[] buff = new Byte[geom.WkbSize()];
geom.ExportToWkb(buff);

//Convert the WKB geometry to SharpMap geometry
SharpMap.Geometries.Geometry sharpMapGeom = GeometryFromWKB.Parse(buff);
geometries.Add(rec);

//Free up resources
geom.Dispose();
}
fea.Dispose();
}
layer.Dispose();
}
//Return the DGN elements formatted as SharpMap geometries
return geometries;
}        

Thursday, December 18, 2008

Create Framme Linkages with FME

FME can be used to write Intergraph Framme linkages. The tricky part is not actually writing the linkages to the graphic DGN elements but figuring out what values to write to the Framme linkages. If you somehow have the correct values from somewhere, then you can use either the FME Workbench or write a FME mapping file to create the linkages.

In this example below, I created an FME mapping file to create DGN line elements with Framme linkages from geometries in a PostGis database table named pipeline. The work is done at the Transformation section of the mapping file as shown in bold below. I am assuming that I have the proper values already calculated and stored as attributes in the PostGis table.

#========================================================================
# Transformation section #======================================================================== POSTGIS pipeline \
postgis_type postgis_line \
i_level %igds_level \
i_color %igds_color \

i_style %igds_style \

i_weight %igds_weight \

i_group %igds_graphic_group \

i_class %igds_class \
ufid %ufid \

feat_num %feat_num \
state_num %state_num \
comp_num %comp_num \
comp_count %comp_count \
dgnfile %dgnfile \
the_geom %geom

IGDS level \
igds_type igds_line \

igds_level %igds_level \

igds_color %igds_color \

igds_style %igds_style \

igds_weight %igds_weight \

igds_graphic_group %igds_graphic_group \
igds_class %igds_class \
geom %geom \
igds_linkage{0}.type framme \

igds_linkage{0}.ufid %ufid \

igds_linkage{0}.feature_num %feat_num \

igds_linkage{0}.state_num %state_num \

igds_linkage{0}.component_num %comp_num \
igds_linkage{0}.comp_count %comp_count \

igds_linkage{0}.design_file %dgnfile

Create DGN Elements on Correct Levels with FME

By default, if you use the FME Workbench or the FME Universal Translator to create a DGN file, the geometries will be created as DGN graphic elements on level 1 and above incrementally for each feature type. For example as shown in the workbench figure below, the destination of my source feature is set to level 1, as indicated with the text "1" in the title bar.


Most times, users will want to control and define the output levels of the output DGN graphic elements since levels is a useful way to organize the graphical data e.g. level 1 for vegetation land use, level 2 for park land use, etc.

In this posting, I describe a way using FME mapping file to define and control the destination level. I am assuming that I have an attribute in the source feature that stores the level number.
  1. Use the FME Universal Translator to generate a mapping file from your source format e.g. ESRI Shape to the destination MicroStation Design format.



  2. Use a text editor to open up the resultant mapping file e.g. mapping.fme.

    The mapping file may look like this.

    # ============================================================================
    # Source feature type definition section
    # ============================================================================

    SHAPE_DEF LAND_USE \
    SHAPE_GEOMETRY shape_polygon \
    USE_TYPE char(50) \
    IGDS_LEVEL number(10,0) \
    ID number(10,0)

    # ============================================================================
    # Transformation section
    # ============================================================================

    SHAPE LAND_USE \
    USE_TYPE %USE_TYPE \
    ID %ID

    IGDS 1 \
    igds_type igds_solid \
    USE_TYPE %USE_TYPE \
    ID %ID


  3. In the Transformation section for the source format, add in the following line in bold.

    SHAPE LAND_USE \
    USE_TYPE %USE_TYPE \
    IGDS_LEVEL %IGDS_LEVEL \
    ID %ID


  4. In the Transformation section for the destination IGDS format, replace the number "1" with the text "level" and add in the following line in bold.

    Note:
    igds_level must be in lower case.

    IGDS level \
    igds_type igds_solid \
    USE_TYPE %USE_TYPE \
    igds_level %IGDS_LEVEL \
    ID %ID


  5. Save the changes and close the mapping file. Now when you run the translation, the DGN graphic elements will be created in the level defined in the IGDS_LEVEL attribute of the source feature.

Wednesday, August 20, 2008

Shape File to DGN Text Elements with Rotation

The Shape file format does not define text geometries; the closest are point geometries with dbf attributes for storing the text properties such as rotation, label string, size. The default FME translation from Shape files to design files will result as point geometries (type 3/4) in the output Microstation design file. To create design files with text elements from shape files, you can use the FME Workbench as follows:
  1. Open up FME Workbench and define a default Shape File to Design File translation.
  2. Bring up the destination design file dataset's properties and enable the igds text properties, e.g. igds_rotation, igds_text_size, igds_text_string, and igds_type.



  3. If the Shape File attribute for storing the text rotation angle is in radians, then you will have to convert the values to degrees using the EXPRESSIONEVALUATOR factory. You can drag and drop the factory and define a new expression &ROT_ANGLE*(180/3.141592) as shown in the screen shot below.



  4. Next, connect up the fields as shown in the screen shot below and attach a constant value igds_text to the igds_type field of the destination dataset.



  5. Run the translation. Your resultant design files will have text elements with rotation, and size applied.

Wednesday, August 13, 2008

Place Microstation Cells in FME

If you want to place Microstation cells from a cell library using the FME Workbench, the following must be done:
  1. In the destination dataset feature type, open up the Feature Type Properties form and enable the igds_type and igds_cell_name Format Attributes property.



  2. Right click on the igds_type property's green arrow and choose to Attach Constant to it. Then key in igds_cell as the constant value. Right click on the igds_cell_name property's green arrow and choose to Attach Constant to it. Key in the cell name e.g. TREE.



  3. Lastly, assign your cell library file to the destination dataset's Cell Library File parameter.



    Note: Make sure that the cell you are placing has a definition in the cell library.