Tuesday, October 23, 2012

Easy C++ Project for Python Use

For this tutorial, I will be using Visual Studios 2010 (C++) and Python 2.7 with ctypes.

Let's assume your boss wants a program that performs addition, there are many ways to write this code, but for the sake of this this tutorial, you want to use the python and C++.
  • Open Visual Studios
  • Follow the steps in creating a project here.
  • Give the project a name called additioncpp
  • Create a header file called 'additioncpp.h' and enter in the following code:
      int sum(int, int);
  •  In the dllmain.cpp file, comment out everything but the '#include "stdafx.h" line
  • Now we are ready to write the sum() we defined in the additioncpp.h header file.  Since python like 'C', and not 'C++' we need to use exten "C" around the functions
      #include "stdafx.h"
      #define DLLEXPORT extern "C" __declspec(dllexport)

      DLLEXPORT int sum(int a, int b) {
          return a + b;
       }

  • Compile the code and copy the .dll to a new folder
  • Create a new .py file and type in the following:
  • print 'start' 
    from ctypes import cdll
    mydll = cdll.LoadLibrary(r'PATHTODLL\additioncpp.dll')
    print mydll
    print mydll.sum
    print mydll.sum(1,2)
    print 'end'
  • You should see an output like this:
>>> 
>>> <_funcptr 0x10ca47b0="0x10ca47b0" at="at" object="object">
>>> 3
>>> end

Enjoy

Monday, October 22, 2012

Exporting C++ Functions for Use in C


If you have functions in a dll written in C++ that you want to access from C, you should declare these functions with C linkage instead of C++ linkage. Unless otherwise specified, the C++ compiler uses C++ type-safe naming (also known as name decoration) and C++ calling conventions, which can be difficult to call from C.
To specify C linkage, specify extern "C" for your function declarations. For example:

   extern "C" __declspec( dllexport ) int MyFunc(long parm1);

 More help can be found here.

Friday, October 19, 2012

What is Extern "C" in C++?

If you are going to use ctypes in python, then you need to export your dll with a C-wrapper.  

You can find a great definition of extent "C" here.  In case you do not want to click on the link, here is what is said by 'Faisal Vali'.

extern "C" makes a function-name in C++ have 'C' linkage so that client C code can use your function using a 'C' compatible header file that contains just the declaration of your function. Your function definition is contained in a binary format that the client 'C' linker will then link to using the 'C' name.  Since C++ has overloading of function names and C does not, the C++ compiler cannot just use the function name as a unique id to link to, so it mangles the name by adding information about the arguments. A C compiler does not need to mangle the name since you can not overload function names in C. When you state that a function has extern "C" linkage in C++, the C++ compiler does not add argument/parameter type information to the name used for linkage.
I couldn't have said it better myself, so I won't


Thursday, October 18, 2012

Setting up C++ Project for Python/ArcGIS Use

This article will discuss setting up a Visual Studios 2010 project to create a DLL using C++ which can be called by python using ctypes.

 1. Open Visual Studios
 2. Create a new C++ Win32 Project
 3. Give it a name, example: simplepythoncpp
 4. Press next 
 5. Select ‘Dll’ for the type of project
 6. Here you’ll have a set of created header files (.h) and Source Files (.cpp)
 7. To use ArcObjects, you need to reference the com libraries.  To do this, you need to tell visual studios where these libraries are.  To set the location, do the follow:
      a. In the Solution explorer, right click and select properties
      b. Select ‘VC++ Directories’
      c. Click on ‘Library Directories’ 
      d. Select ‘Edit’
      e. Navigate to the ArcGIS 10.1 install directory and select the ‘com’ folder
 8. Staying in the properties, we need to enable ‘C++/CLI’ 
      a. Click on ‘Command Lin’
      b. Under ‘Additional Options’ type ‘/clr’
 9. Next we need to define some ‘Code Generation’ options
      a. Click on ‘Code Generation’
      b. Under ‘Basic Runtime Checks’ select ‘Default’
 10. Press ‘Apply’ button then ‘OK’
Let’s test our project changes.
 1. Open the ‘stdafx.h’ header file
 2. Leave the default #include statements, and type in the following:

#import "esriSystem.olb" raw_interfaces_only, raw_native_types, no_namespace, named_guids, exclude("OLE_COLOR", "OLE_HANDLE", "VARTYPE")

 3. Compile project
No errors should appear, so your project is setup correct.  
Where do you do from here? Well, all the libraries you need in this header file, and reference them in your .cpp file.  

Wednesday, October 17, 2012

c++ and python = woot!

Everything old is new, and so begin my venture back into the C++.  My focus now is using C++ libraries with ArcObjects, slightly different then what I did way back in the before times.  

Some tips:

  • Create a DLL project and ensure that the ArcGIS/com folder is mapped to the project properties -> 'VC++ Directories' -> 'Include Directories'
  • get comfortable with resources.arcgis.com and the Visual Studios help system
  • Experiment and push the limits
Enjoy the ride

Tuesday, October 9, 2012

ArcGIS 10.1 and matplotlib

Graphing at 10.1 is now easier because ArcGIS comes with matplotlib.  To me, this is an exciting enhancement that broadens what python developers can do when it comes to visualization of data in ArcGIS.

A simple example of this is the basic X/Y plot but instead of using random number, assume we have a table and the X/Y (distance/elevation) is in your table.

Example:

import arcpy
import os
import matplotlib.pyplot as plt
x = []
y = []

elevPNG = env.scratchFolder + os.sep + "elev.png"
fig = plt.figure()
table = r"C:\temp\scratch.gdb\data"
fields = ["FIRST_DIST", "FIRST_Z"]
with arcpy.da.SearchCursor(table, fields) as rows:
    for row in rows:
        x.append(row[0])
        y.append(row[1])
plt.plot(x,y, color='r')
plt.xlabel('Distance From Start Location')
plt.ylabel('Elevation')
plt.title('Landscape Profile')
fig.savefig(elevPNG, dpi=fig.dpi)


So what has happened, is that the x and y information is stored in a 1:1 fashion in list objects.  The figure is created and lists populated using a simple search cursor.  The line graph is shown using the plot() and labels are added to make the graph easier to read.

The results is something like this:
In this application, a user can quickly assess the terrain without examining each elevation point, and can determine if a better route is needed.


Friday, October 5, 2012

Archiving Made Easy at Python 2.7

At python 2.7, there is a great shutil tool called make_archive().  It can make either a .zip or .tar file, and eliminates the need to create a walking function to compress files.

The function supports the following compression types by default:
  • zip
  • bztar
  • gztar
  • tar
But if you have another format, you can register it using the register_archive_format().

Example:
compressFile = shutil.make_archive(r"c:\temp\mycompressfile", "zip", r"c:\temp\data")
Notice that the first parameter doesn't have the file extension.  The function will return the path to the newly created compressed file.

To uncompress the file, you will have to do that manually using zipfile or tarfile modules.

Enjoy