The Tool - Download

For a long time I’ve wanted a quick way to spot check if structural beams in our analysis models like RAM or ETABs matched our Revit model. The gif above shows the beginning of bringing this idea to life. The tool will be a plugin for Revit that will allow users to import their RAM structural model into an in-between file that will interact with RAM and Revit.

I'm a little sad that I am not developing this tool for ETABs, as this is my daily structural analysis driver, but our office is much more of RAM office than ETABs office. Gotta do what the people want and will (hopefully) use.

How It Works

The initial screen is split between a RAM Structural side (left) and a Revit side (right). After pointing the program to the location of the RAM SS model, the user will collect the levels and select the level of interest in the combo box. From here, the program will gather the structural grids in the RAM SS model and plot them onto the RAM canvas. A similar process occurs on the Revit side to plot all of the grids in the Revit model.

From here, the user will be promoted to select two interesting gridlines that will share the same coordinates in both the RAM model and Revit model. This intersection will be use in future to generate the global coordinate system for the project as a whole, allowing for the RAM and Revit model to have differing coordinate systems and still map into each other.

Next Steps

The mapping algorithm. The way the project is currently constructed, the program will determine the x and y offset by calculating the intersection point of the selected RAM and Revit grids.

From here, I will work on a function to determine the rotation parameter. This might be a bit tricky to determine, given that a rotation parameter could either be positive or negative, I might prompt the user to select the rotation parameter.

With the x, y and rotation parameters set, I can set up the local coordinate system for the RAM beams and map them in the global coordinate system of the revit project.

Fun Parts of the Coding Experience

It’s funny how many pieces of my previous coding experience came into play making this.

  • Canvas and graphics
    • A lot of the lessons I learned in javascript and threejs from the concrete design tool were able to be applied to the plotting performed in this script.
    • Do not forget that the default canvas is coordinates have the y coordinate being negative. This threw me for a loop for a bit trying to trouble shoot why the grid plots were always upside down
  • Intricate point class
    • The r2rPoint class is on the upper end of my ability to understand classes in C#. There are some very complicated properties and methods used in the class and it is a big improvement from the point class utilized in the section cutter tool. It allows the point to be defined in either the global (GCS) or local coordinate system (LCS)
    • This came in handy when pulling grid data out RAM structural due to the grid system definition. Essentially each grid system in RAM structural has its own local coordinate system that the r2rPoint class can handle quite elegantly. The way a point is defined as global or local is through the isGlobal Boolean.
    //Initialize the point class in either the global or local coordinate system thru isGlobal Flag

        public r2rPoint(double X, double Y, double Z)
            this.X = X;
            this.Y = Y;
            this.Z = Z;
            isGlobal = true;

        public r2rPoint(double U, double V, double W, bool isGlobal = false)
            this.U = U;
            this.V = V;
            this.W = W;
            this.isGlobal = isGlobal;

        public void Convert_To_Local(GlobalCoordinateSystem gcs)
            double[] part1 = new double[] { X - gcs.RefPnt[0], Y - gcs.RefPnt[1], Z - gcs.RefPnt[2] };

            //the class will now have new attribute of local coordinates point.LocalCoords[0] = the X local coordinate system
            LocalCoords = new List<double>() { gcs.R_Inv[0, 0] * part1[0] + gcs.R_Inv[0, 1] * part1[1] + gcs.R_Inv[0, 2] * part1[2] ,
            gcs.R_Inv[1, 0] * part1[0] + gcs.R_Inv[1, 1] * part1[1] + gcs.R_Inv[1, 2] * part1[2],
            gcs.R_Inv[2, 0] * part1[0] + gcs.R_Inv[2, 1] * part1[1] + gcs.R_Inv[2, 2] * part1[2]};

            this.U = LocalCoords[0];
            this.V = LocalCoords[1];
            this.W = LocalCoords[2];

        public void Convert_To_Global(GlobalCoordinateSystem gcs)
            //this is the ref point
            double[] part1 = new double[] { U, V, W };

            //the class will now have new attribute of local coordinates point.LocalCoords[0] = the X local coordinate system
            GlobalCoords = new List<double>() { (gcs.R[0, 0] * U + gcs.R[0, 1] * V + gcs.R[0, 2] * W) + gcs.RefPnt[0],
            (gcs.R[1, 0] * U + gcs.R[1, 1] * V + gcs.R[1, 2] * W) + gcs.RefPnt[1],
            (gcs.R[2, 0] * U + gcs.R[2, 1] * V + gcs.R[2, 2] * W) + 0}; //unsure why this the way to do this. review in the future. should be the line below, without the 0
            //(globalCoords.R[2, 0] * X + globalCoords.R[2, 1] * Y + globalCoords.R[2, 2] * Z) + globalCoords.RefPnt[2]};

            this.X = GlobalCoords[0];
            this.Y = GlobalCoords[1];
            this.Z = GlobalCoords[2];

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName)
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

Each grid system in RAM structural has it's own local corodinate system:

  • Xaml and Html Similarities
    • This is the first time I have used XAML and WPF (Note, someday I dream of experiencing less "first"s in programming. The programming world seems so large and ever expanding compared to that of structural engineering where it is the same old stuff day in and day). Xaml looks very similar to Html, Maybe Xaml stole some ideas from Html? </> formats are familiar from brief experience in web development and getting this website up and running. It did not take too long to make the Xaml work, which I attribute to having some background in Html. 
      • I learned from some previous coworkers that Xaml and WPF is a more "modern" approach to UI development compared to winforms which was used to make the sectioncutter ui. Personally, I find winforms super easy to get up and running, but for more complicated projects like this one, maybe xalm and WPF will pay off.
  • ChatGPT Skills
    • I am continually amazed by ChatGPT and it’s ability to get thing up and running quickly
    • 90% of my canvas events were written by ChatGPT and it’s really impressive how quickly ChatGPT was able to take me from an idea to a functional example, allowing me to fill in the blanks
    • I originally went down the route of using LiveCharts2 to do the interactive plotting, which I wasted a lot of time exploring. ChatGPT could not help me due to the fact that LiveCharts2 was not released until 2022. ChatGPT was really good at making up stuff that used to work in the original LiveCharts and that would not work in LiveCharts2. I eventually gave up and went to the old fanshioned canvas to handle events and plotting needs.
    • I wrote the concrete design tool before ChatGPT and I would estimate that it took me about 3 solid weeks of coding and internet forum conversations to get a workable zoom, pan and selection function to work with the canvas. ChatGPT was able to write these functions in the better part of a 20 min interaction with it. Super impressive.
    • I find myself having to thank the robot overlord all the time for the work that it does for me : ), I am not sure if others do this as well.
Me: I get an error that Ellipse does not contain a definition for child

ChatGPT: I apologize for the confusion. My previous response contained incorrect information. Ellipse does not have a direct Child property to add text inside it. Instead, you can achieve this by placing both the Ellipse and TextBlock inside a container like a Grid. Here's how you can do it:

Copy code
private void AddCircleWithText(double x, double y, string text)
    Grid container = new Grid();

    Ellipse circle = new Ellipse
        Width = 10, // Diameter = 2 * Radius
        Height = 10, // Diameter = 2 * Radius
        Fill = Brushes.Red,
        Stroke = Brushes.Black,
        StrokeThickness = 1,

    TextBlock textBlock = new TextBlock
        Text = text,
        Foreground = Brushes.White,
        HorizontalAlignment = HorizontalAlignment.Center,
        VerticalAlignment = VerticalAlignment.Center


    // Position the container at (x, y)
    Canvas.SetLeft(container, x - 5); // Adjust for the radius
    Canvas.SetTop(container, y - 5); // Adjust for the radius


Now, each circle and text combination is enclosed in a Grid, which allows you to display text inside the circle on the canvas. You can use the AddCircleWithText function with the (x, y) coordinates for the center of the circle and the desired text to place inside it.

Me: This looks great thank you! How can I make it so that the elements in the canvas are larger on my screen via scrolling in and out?

Another oddity about the code, when accessing the RAM structural API, I needed to add a reference to the Microfsoft.CSharp .dll. I had never had to do this before in my previous experience following Marcello’s examples, but the binding functions and casting functions would not work without import the CSharp reference. After some confusion and googling, I was able to resolve this error.

Please note that this code is not DRY (do not repeat yourself), I would like to come back in the future and make it more DRY, many of the canvas functions are duplicated, one with ramZoom or revitZoom. I bet there is a way to make this work without repetitive canvas events.

Future Work

  • Keep going on point mapping algorithm
  • Add a save and read functionality to store the mapping parameters
    • I have not done save and read before in my programming experience so this should be a good learning experience.
  • Address radial grids
    • Both RAM and Revit
  • Address that RAM grids only work with a max and min parameter set.
  • Add zoom to fit function
    • Right now the grids are not centered in the canvas. Maybe add a double middle mouse button click to zoom extents.

BIM Revit RAM C Sharp

Our Sidebar

You can put any information here you'd like.

  • Latest Comments
  • Liz_Larsen on R2R - Update V1.1.0 -

    Great job! We've been wanting a tool like this for so long that I'd considered making it myself. During my research, I stumbled across this blog right around the time you were looking for testers a few months ago. 

    I'll be sure to spread the word about this amazing tool. Thanks …

  • retug on ETABs API - More Examples (Database Tables) -

    Hi rajavardhan, are you not able to delete selected frames and walls based on section properties through the ETABs program itself? Or through the API? I could put together a few quick examples for you with the API if needed.

  • rajavardhan on ETABs API - More Examples (Database Tables) -

    Hi, I am not able to select frames and walls based on section properties in etabs v21 and then delete selected frames and walls..can anyone suggest me the code to do it use Excel VBA code