Tag Archives: ArcGIS Desktop Explorer

Send MMS from ArcGIS Desktop Explorer – or Revit.

2 May
MMS from a button in Desktop Explorer.

MMS from a button in Desktop Explorer.

I had an earlier post on sending an MMS from C#. I have taken it one step further and dropped this code in to ArcGIS Desktop Explorer as a button. click the button and it takes a screenshot, pops up a form and attaches the screenshot. Can send as email or as an MMS. This should work for Revit too since the SDK is C# and all the code is from Microsoft not the GIS API.

 

When launching a form from the buttons in GIS, threading becomes an issue. Note the use of ShowDialog().  Also, in order to caputure the screen without the form in the way, grab it before launching the form. This is how you launch a form from the button in GIS:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Net.Mail;
using System.Windows.Forms;
using System.Drawing.Imaging;

using ESRI.ArcGISExplorer;
using ESRI.ArcGISExplorer.Application;
using ESRI.ArcGISExplorer.Mapping;
using ESRI.ArcGISExplorer.Geometry;
using ESRI.ArcGISExplorer.Data;
using ESRI.ArcGISExplorer.Threading;

namespace geomms
{
public class Button : ESRI.ArcGISExplorer.Application.Button
{

public override void OnClick()
{
int screenWidth = Screen.GetBounds(new System.Drawing.Point(0, 0)).Width;
int screenHeight = Screen.GetBounds(new System.Drawing.Point(0, 0)).Height;
Bitmap bmpScreenShot = new Bitmap(screenWidth, screenHeight);
Graphics gfx = Graphics.FromImage((Image)bmpScreenShot);
gfx.CopyFromScreen(0, 0, 0, 0, new Size(screenWidth, screenHeight));
bmpScreenShot.Save(“test.jpg”, ImageFormat.Jpeg);

Form1 a = new Form1();
a.ShowDialog();

}
}
}

 

 

Here is the code to send the MMS:

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Mail;
using System.Drawing.Imaging;

namespace geomms
{
public partial class Form1 : Form
{

public Form1()
{
InitializeComponent();

}

private void button1_Click(object sender, EventArgs e)
{
try
{
String strFileName = string.Empty;
MailMessage mail = new MailMessage();
SmtpClient SmtpServer = new SmtpClient(“embudo.cabq.gov”);
mail.From = new MailAddress(“pcrickard@cabq.gov”);
mail.To.Add(tobox.Text.ToString());
mail.Subject = subjbox.Text.ToString();
mail.Body = msgbox.Text.ToString();
strFileName = “test.jpg”;
System.Net.Mail.Attachment attachment;
attachment = new System.Net.Mail.Attachment(strFileName);
mail.Attachments.Add(attachment);

SmtpServer.Send(mail);
MessageBox.Show(“Sent Message”, “MMS by Paul”);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}

 

Auto Message Popups in ArcGIS Desktop Explorer From RabbitMQ

19 Apr
Message sent from terminal to ArcGIS Desktop Explorer Extension.

Message sent from terminal to ArcGIS Desktop Explorer Extension.

My previous post showed how to send messages to GIS from a terminal using Python-Pika, RabbitMQ, and C#. It required the user to click a button to receive them. I have modified code from several sources to make it run on a thread- as an extension to ArcGIS Desktop Explorer. Every 2 seconds, the extension checks for messages.

I modified code from:

LosTechies – For C#.

RabbitMQ Tutorial – For Python Producer.

And the ArcGIS Resource Center for the threading info.

I can send you the Addin .EAZ if you wish. Here is what I came up with:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using RabbitMQ.Client;

using ESRI.ArcGISExplorer;
using ESRI.ArcGISExplorer.Application;
using ESRI.ArcGISExplorer.Mapping;
using ESRI.ArcGISExplorer.Geometry;
using ESRI.ArcGISExplorer.Data;
using ESRI.ArcGISExplorer.Threading;
namespace RabbitMQgisExtension
{
public class Extension : ESRI.ArcGISExplorer.Application.Extension
{
string msg;
static IConnection connection;
static IModel channel;
System.Timers.Timer _t = new System.Timers.Timer(2000);

public override void OnStartup()
{
_t.Start();
_t.Elapsed += new System.Timers.ElapsedEventHandler(_t_Elapsed);

}

public override void OnShutdown()
{
_t.Stop();
channel.Close();
connection.Close();
}

void _t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
var connectionFactory = new ConnectionFactory();

connection = connectionFactory.CreateConnection();
channel = connection.CreateModel();
channel.ExchangeDeclare(“GIS”, ExchangeType.Direct);
channel.QueueDeclare(“GIS”, false, false, false, null);
channel.QueueBind(“GIS”, “GIS”, “PAUL”);
BasicGetResult result = channel.BasicGet(“GIS”, true);

if (result != null)
{
msg = Encoding.UTF8.GetString(result.Body);
MessageBox.Show(msg, “You’ve Got a Message!”);
//If set Message to send coords in form “35,-106” Next lines will draw points.
//string[] coords = msg.Split(‘,’);
// float x = float.Parse(coords[0]);
// float y = float.Parse(coords[1]);
//Note fromRabbit = new Note(“From RabbitMQ”, new ESRI.ArcGISExplorer.Geometry.Point(y, x));
//ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay.Map.ChildItems.Add(fromRabbit);
}
}

 

and the Python Producer – EXAMPLE: python send.py KEY TEXT

(python send.py PAUL message to you):

import pika
import sys

connection = pika.BlockingConnection(pika.ConnectionParameters(
host=’localhost’))
channel = connection.channel()

channel.exchange_declare(exchange=’GIS’,
type=’direct’)

to = sys.argv[1]
message = ‘ ‘.join(sys.argv[2:])

channel.basic_publish(exchange=’GIS’,
routing_key=to,
body=message)
print “Sent %r:%r” % (to, message)
connection.close()

Send Message to GIS or Revit from a Terminal using RabbitMQ, Python, Pika and C#

19 Apr

I have been playing with messaging in software applications. Using RabbitMQ, C# and Python, I got the bright idea to send messages to GIS from a python console – which will later be another program or windows form, but for demo purposes I just needed to verify the possibility. The SDK for my GIS is in C#, and so is the SDK for Revit.
I will show you what I did in GIS and then explain how this would work in Revit.
First, I sent a message to the GIS software.
20130419-081234.jpg
The DOS window is my command center that sends the messages. You can see that there are two commands: one has JOE and one has PAUL in it. You can send messages to every listener, or you can specify a keyword or word pattern – in this case PAUL and JOE are the keywords. My GIS app will only receive messages sent to PAUL. When you click the button, it grabs all waiting messages.
If I can send text, I can send data too. What if I send coordinates? I can draw them in the map.
20130419-081352.jpg
Now it takes the message and does something with it. This example has the sender and receiver on the same machine, but they do not have to be. So for Revit, what if we had a window that could update schedules in Revit with data. A user could input the data and the Revit user could press a button to update the model with the new data. Perfect for additional fields in a schedule. Or you could set it to run as a thread so when a message comes in the box pops up automatically. Here is the Code for the Plugin:
string msg = null;
var connectionFactory = new ConnectionFactory();
IConnection connection = connectionFactory.CreateConnection();
IModel channel = connection.CreateModel();
channel.ExchangeDeclare(“GIS”,ExchangeType.Direct);
channel.QueueDeclare(“GIS”,false,false,false,null);
channel.QueueBind(“GIS”,”GIS”,”PAUL”);
BasicGetResult result = channel.BasicGet(“GIS”, true);
if (result != null)
{
msg = Encoding.UTF8.GetString(result.Body);
MessageBox.Show(msg, “Status”);

}
else
{
MessageBox.Show(“No Messages Waiting.”, “Status”);
}
And the sender in python:
import pika
import sys
connection = pika.BlockingConnection(pika.ConnectionParameters(
host=’localhost’))
channel = connection.channel()
channel.exchange_declare(exchange=’GIS’,
type=’direct’)
to = sys.argv[1]
message = ‘ ‘.join(sys.argv[2:])
channel.basic_publish(exchange=’GIS’,
routing_key=to,
body=message)
print “Sent %r:%r” % (to, message)
connection.close()

Public Safety GIS 2: Python, MongoDB, C# and ArcGIS Desktop Explorer

17 Apr

I wrote a plugin for ArcGIS Desktop explorer that called a python script and passed the map center as an argument. The python script queried a MongoDB and wrote out a csv of closest points. The button then loads the csv as points. I had to do this because I didn’t know how to do it in C#. Well, I figured it out.

Now C# does all the work querying the database and drawing the points. I still have a python script that reads data from a csv export from sharepoint, geocodes it and creates the mongoDB.

Here is my code:

PYTHON TO CREATE THE DB:

from pymongo import Connection,GEO2D
import urllib, urllib2, simplejson
import csv

data = csv.reader(open(‘C:\Documents and Settings…\myfile.csv’))
fields=data.next()
db=Connection().rtcc
db.cnau.create_index([(“loc”,GEO2D)])

for row in data:
try:
address=row[0]
combinedaddress=address+”,albuquerque, NM”

param = {‘q’: combinedaddress,’output’: ‘json’, ‘oe’: ‘utf8’}
url = ‘http://maps.google.com/maps/geo?’ + urllib.urlencode(param)
rawreply = urllib2.urlopen(url).read()
reply = simplejson.loads(rawreply)
print reply[‘Placemark’][0][‘Point’][‘coordinates’][0]
long=reply[‘Placemark’][0][‘Point’][‘coordinates’][0]
lat=reply[‘Placemark’][0][‘Point’][‘coordinates’][1]
z={“loc”:[long,lat],”Activity”:row[1]}

db.cnau.insert(z)
except KeyError:
pass

 

C# TO PLUGIN ARCGIS DESKTOP EXLPORER:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ESRI.ArcGISExplorer;
using ESRI.ArcGISExplorer.Application;
using ESRI.ArcGISExplorer.Mapping;
using ESRI.ArcGISExplorer.Geometry;
using ESRI.ArcGISExplorer.Data;
using ESRI.ArcGISExplorer.Threading;

using MongoDB;
using MongoDB.Bson;
using MongoDB.Driver.Linq;
using MongoDB.Driver;
using MongoDB.Driver.Builders;

namespace MongoC
{
public class Button : ESRI.ArcGISExplorer.Application.Button
{

public override void OnClick()
{

Folder folderMapItem = new Folder();
MapDisplay mdisp = ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay;

//use this to change the projections 35,-106
FeatureLayer proj = FeatureLayer.OpenShapefile(“C:\\Documents and Settings…\\forProjection.shp”);
// Path for Windows 7: FeatureLayer proj = FeatureLayer.OpenShapefile(“C:\\Users\\user\\…\\forProjection.shp”);
mdisp.CoordinateSystem2D = proj.CoordinateSystem;
string center = mdisp.Center.ToString();
folderMapItem.Name = “Close To Me”;
string[] c = center.Split(null);
String lon = c[3];
String lat = c[6];

MongoClient client = new MongoClient(); // connect to localhost. Deploy at: “mongodb://ip.of.host:27017”
MongoServer server = client.GetServer();
MongoDatabase db = server.GetDatabase(“rtcc”);

var collection = db.GetCollection<BsonDocument>(“cnau”);

var query = Query.Near(“loc”, double.Parse(c[3]), double.Parse(c[6]));
//var cursor = collection.Find(query); Put this in foreach so dont need it anymore.
foreach (BsonDocument item in collection.Find(query).SetLimit(5))
{
BsonElement loc = item.GetElement(“loc”);
string g = loc.Value.ToString();
string x = g.Trim(new Char[] { ‘[‘, ‘]’ });
String[] a = x.Split(‘,’);
// BsonElement name = item.GetElement(“name”); Work for all indexes in MongoDB
// Pass the other data to the notes popups below

ESRI.ArcGISExplorer.Geometry.Point mypoint = new ESRI.ArcGISExplorer.Geometry.Point(double.Parse(a[0]), double.Parse(a[1]));

// Create a Note using the Point geometry.
Note mypointNote = new Note(“MyNote”, mypoint, Symbol.Marker.Pushpin.Orange);

// Populate the Note popup with information about the Point geometry using the ToString method.
StringBuilder info = new StringBuilder(@”<p><a href=””http://google.com””>Google</a></p>&#8221;);
info.AppendLine(@”<p>” + mypoint.ToString() + @”</p>”);

//MapDisplay disp = ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay;
mypointNote.Popup.Content = info.ToString();

// Add the Note to the current Map.
//mdisp.Map.ChildItems.Add(mypointNote);
folderMapItem.ChildItems.Add(mypointNote);
}

mdisp.Map.ChildItems.Add(folderMapItem);
}
}
}

Launch External Script in ArcGIS Desktop Explorer

24 Jan

arcgis_explorer_15001

I have started to toy with the ArcGIS Desktop Explorer API. My first few attempts at functionality required only the use of C# Libraries and not the actual SDK Library – with the exception of getting the button in.

If you have the SDK installed, you can start a new project in Visual Studio Express and select the GIS Button. This first example will allow you to execute a script or program on your machine. Where it tells you to insert your code, enter the following line:

 System.Diagnostics.Process.Start(“myPythonFile.py”);

This will run the python file. You could also use launch system applications like calc or notepad.

My next test was to launch a website from a button.  Same as the above, except enter the URL of the site. This will open the page in your default browser.

System.Diagnostics.Process.Start(“http://google.com&#8221;);

One thing I had trouble with was how do I add several buttons in a single Namespace? I copied the button that was created by default and pasted it in to the namespace. Then you need to change the name and the functionality. Lastly, you need to edit the AddIns.xml file. Copy the first button and paste it. Then modify the values to math your new button. I have put the values that MUST change in bold. You should change the captions too. Also, drag any images to the images folder. 32×32 for large and 16×16 for small.

<button
id=”Button1
assembly=”WebLaunchButtons.dll”
className=”WebLaunchButtons.Button1
caption=”Google”
tooltip=”Quick Access to Google.”
helpString=”http://mydomain.com&#8221;
largeImage=”Images\google.png”
smallImage=”Images\google_SmallImage.png” />

<button
id=”Button2
assembly=”WebLaunchButtons.dll”
className=”WebLaunchButtons.Button2
caption=”Yahoo!”
tooltip=”Quick Access to Yahoo.”
helpString=”http://mydomain.com&#8221;
largeImage=”Images\yahoo.png”
smallImage=”Images\yahoo_SmallImage.png” />

Now you will have 2 buttons in a frame with a single group title – you set this in the initial project settings.

My last example will connect to an FTP site, grab a shapefile, and load it. The code is a mashup of code from MSDN and ESRI as well as some modifications on my part.

public override void OnClick()
        {
            m_disp = ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay;

            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(“ftp://ftp1.freebsd.org/pub/FreeBSD/README.TXT”); //this would be to a shapefile but I dont have an FTP server.
            request.Method = WebRequestMethods.Ftp.DownloadFile;

           
            //request.Credentials = new NetworkCredential(“me”, “mypassword”);

            FtpWebResponse response = (FtpWebResponse)request.GetResponse();

            Stream responseStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(responseStream);
            System.IO.StreamWriter file = new System.IO.StreamWriter(“c:\\downloaded.txt”); //your shapefile
            file.WriteLine(reader.ReadToEnd());
            
            reader.Close();
            response.Close();
            file.Close();

            FeatureLayer fl = FeatureLayer.OpenShapefile(“C:\\downloaded.shp”); // the file you saved
            fl.Renderer.SetSymbol(CreateSymbol(fl.GeometryType));
            m_disp.Map.ChildItems.Add(fl);
            m_disp.ZoomTo(fl.Extent);

            
        }

        private Symbol CreateSymbol(GeometryType geomType)
        {
            //Create a new symbol for the feature layer data being added based on feature type
            Symbol sym = null;
            switch (geomType)
            {
                case GeometryType.Point:
                    sym = Symbol.Marker.Pushpin.LightBlue;
                    break;
                case GeometryType.Polygon:
                    sym = Symbol.CreateFill(System.Drawing.Color.Aqua, System.Drawing.Color.Black);
                    break;
                case GeometryType.Polyline:
                    sym = Symbol.Line.Solid.Purple;
                    break;
            }

            return sym;
        }

    }

In my next post, I will show how to send an SMS text message from GIS.