Posts by retug (36)

Section Cutter - ETABs Plugin

Install

https://www.youtube.com/watch?v=CUDt8zJYAoc

How to use

https://www.youtube.com/watch?v=L_XXPHafNQQ

A major upgrade to the section cutter tool, section cuts are now centered on the first and last location where they pass through constituent area geometry. An astute engineer in our office noticed that if the section cuts were not centered on the constituent area geometry, moment results could be quite skewed as ETABs reports moments about the center of the section cut, not the center of the cut geometry. Let's dig into the algorithm and code.

A new github repo has been created for the section cutter tool. This project has become big enough that it deserves it's own repo. The readme page also has install instructions.

The "Smart Sections Algorithm"

The algorithm to make "smart" sections was easy to do on paper, a bit harder to do by painstakingly describing every step to a computer. Let's get some visual aids to assist in outlining the algorithm.

 Step 1 - Gather User Areas and Input Node. Example will be a simple square.

Note, I think the input node could be omitted, but it has remained in the section cutter tool for now.

Step 2 - Setup Local Coordinate System (LCS) based on input vector and starting point.

Here the LCS is rotated 45 degrees as shown by the blue rotated grid lines. Convert all constituent area geometry to the LCS. LCS coordinates in Red.

 

Step 3 - Generate an array lines in the LCS.

The previous section cutter tool would stop at this point. These results would be incorrect for buildings with steps, like an L shaped diaphragm.

Step 4 - Determine where lines generated in step 3 cross constituent geometry.

Use these points to create the section cuts in ETABs.

The Code

The main struggle on the coding side was controlling all the lists of data and maintaining their structure. The algorithm works for many areas and openings, so the amount of data that gets generated to perform these checks inflates quite quickly. To my surprise, the tool does not seem to struggle with generating all of the section cut data, the slowest part is still the analysis of the semi-rigid diaphragm.

Once again, chatGPT really helped out with the coding. The intersection function was exactly copied and pasted and it worked, how surprising!

Here is my chat with the AI overlord bot, THEY TOOK OUR JOBS! :

Me: Given that two line segments, each with an x and y value, that are known to intersect, write c# code that determines the intersection point, x and y, of the two line segments

ChatGPT

To find the intersection point of two line segments, you can use the concept of parametric equations. Given two line segments defined by their endpoints (x1, y1) to (x2, y2) and (x3, y3) to (x4, y4), you can calculate the intersection point (xi, yi) using C# code as follows:

using System;

class Program
{
    static void Main()
    {
        // Example endpoints of two line segments
        int x1 = 1, y1 = 2;
        int x2 = 4, y2 = 6;
        int x3 = 3, y3 = 1;
        int x4 = 5, y4 = 5;

        // Calculate the intersection point
        if (Intersect(x1, y1, x2, y2, x3, y3, x4, y4, out int xi, out int yi))
        {
            Console.WriteLine($"Intersection Point: ({xi}, {yi})");
        }
        else
        {
            Console.WriteLine("The line segments do not intersect.");
        }
    }

    // Function to check if two line segments intersect and calculate the intersection point
    static bool Intersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, out int xi, out int yi)
    {
        // Calculate the denominator for parametric equations
        int denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);

        // Check if the line segments are parallel or coincident
        if (denominator == 0)
        {
            xi = 0;
            yi = 0;
            return false;
        }

        // Calculate the parameters for each line segment
        int ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
        int ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;

        // Check if the intersection point lies within both line segments
        if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
        {
            // Calculate the intersection point
            xi = x1 + ua * (x2 - x1);
            yi = y1 + ua * (y2 - y1);
            return true;
        }

        xi = 0;
        yi = 0;
        return false;
    }
}

Replace the example endpoints (x1, y1, x2, y2, x3, y3, x4, y4) with the actual endpoints of your line segments. The code will then calculate the intersection point (xi, yi) if the two line segments intersect, or indicate that they do not intersect.

ChatGPT used an expression "out" that I had never seen before and it was super helpful. I still need to read up on "out" and "ref" in C#, but these seem to be ways to add additional function returns in C#.

Throwing this function into the main portion of the code, I was able to perform step 4 of the algorithm outlined above. Working in the LCS system was nice, allowing for easy manipulations of items that were perpendicular/parallel to the LCS. With the LCS point geometry known, it was easy to convert back into the GCS.

In addition to the main "smart sections" addition, a few features were added

  • For Trenno, Imperial (kip, ft), freedom units, and Metric (kN, m), superior units, results.
  • Section Cut plot at the bottom of the graphical user interface has been updated to look better.
  • A few more data validations items on user input have been added

I have more updates I want to get around to listed on the github repo readme page. If you have suggestions/bugs, please let me know. Looking to make this better.

Project Management with Deltek

Deltek is a powerful tool to track all things AEC related. At my level, I use it mostly for project management and tracking project budgets. 

You can get a lot of powerful reports out of it quickly, but at face value, it's just a sea of data. We need to visualize this data to get a better feel for what's happening. The plot above shows hours on a fictitious project over time for differing employees.

Fun notes from fake project, brown engineer leaves company, olive main engineer goes back to school mid project, blue project manager scrambles to pick up the project mid way through.

If you use deltek, you can quickly get this data in an excel format from the project review tab and clicking "export to excel". 

The sample excel file will have the following format:

Person Date Hrs Checked
Help Proj Eng 1 10/14/2021 4 Checked
QAQC Eng   15  
QAQC Eng 9/14/2022 4 Checked
QAQC Eng 12/6/2022 2 Checked
QAQC Eng 5/8/2023 1 Unchecked
QA/QC Eng 5/9/2023 6 Unchecked
QA/QC Eng 5/10/2023 2 Unchecked
Help Eng 2   10  
Help Eng 2 11/21/2022 0.5 Checked
Help Eng 2 11/22/2022 5.5 Checked
Help Eng 2 11/23/2022 4 Checked
Drafter QAQC   4.5  
Drafter QAQC 4/27/2023 4.5 Checked
Drafter QAQC 5/15/2023 0 Unchecked
Proj Eng 3   130  
Proj Eng 3 9/15/2022 0.5 Checked

With this excel file, we can do a little python on the file, using pandas and matplotlib and create fun plots.

I am still quite a beginner with pandas and I am sure there is a much more elegant way to do the cumulative time vs date plot. I struggled through this, but the code works:

 

### Multiple Plots

df_all = pd.read_excel('H:\\MyGenericProject.xlsx', sheet_name = 'HoursForProject')
names = df_all.iloc[:,0]

my_column_changes = names.shift() != names        
index_change = [i for i, x in enumerate(my_column_changes) if x]

PersonHrs = {}
PersonDate = {}

for i in range(len(index_change)):
    if i == len(index_change)-1:
        print(i)
        PersonHrs[names[index_change[i]+1]] = df_all.iloc[index_change[i]+1:,2]
        PersonDate[names[index_change[i]+1]] = df_all.iloc[index_change[i]+1:,1]
        
    else: ###grabs the last person in the list
        print(i)
        PersonHrs[names[index_change[i]+1]] = df_all.iloc[index_change[i]+1:index_change[i+1],2]
        PersonDate[names[index_change[i]+1]] = df_all.iloc[index_change[i]+1:index_change[i+1],1]
    
sum_time = []
for i in PersonHrs.values():
    indiv_sum = []
    indiv_time = 0
    for time in i:
        indiv_time += time
        indiv_sum.append(indiv_time)
    sum_time.append(indiv_sum)
    
for indiv_person_hrs, indiv_person_date in zip(sum_time, PersonDate.values()):
    DF = pd.DataFrame()
    DF['value'] = indiv_person_hrs
    
    person_date = pd.to_datetime(indiv_person_date) 
    DF = DF.set_index(person_date)
    
    plt.plot(DF)
    plt.gcf().autofmt_xdate()

plt.legend(PersonDate.keys())
plt.show()

The code to do this and sample excel file is found on github.

In addition, I made a cool stacked bar plot that tracks hours on Engineering, Drafting and QA/QC type work.

This fake project worked out to be about 70% engineering, 23% drafting and 7% QA/QC.

Moving forward, I would like to access Deltek's API directly. It would be awesome to make these plots directly without having to export excel files and pull other data manually. If you have accessed Deltek's API before, let me know, it would be fun to explore how to do this.

 

Transfer Diaphragm Design

I have been working through some complicated diaphragm designs with a newer engineer recently and have been learning a lot about transfer diaphragms. I realized I was falling into some pitfalls and it was good working through this with the newer engineer. One of the great things about working with newer engineers is the fresh perspective and inquisitive nature.

The Sample Building

The building shown at the start of this blog post is a 20 story tall building, with the lower (2) floors being the typical transfer diaphragm type building, where the building core shifts a lot of its lateral load out to the perimeter concrete walls. See image below for large jump in shear at the transfer diaphragm in the building we inspect in this post.

I want to note that this building is completely made up, please take all numbers with a grain of salt and let’s focus on the relative values, not the values themselves. Please also let me know if you do diaphragm design differently, this is one person's perspective on diaphragm design.

A few notes on the building.

  • Total height 248ft
  • Typical story height is 12ft
  • 24” thick concrete core with moment frame outrigger system
  • 12” thick concrete slab for typical floor
  • 24” transfer diaphragms at levels 2 and 1
    • We will study a few differing transfer diaphragm setups
    • Level 2 Shown below

  • Building is subjected to an ELF type load
    • Base ETABs seismic seismic parameters
      • R = 8
      • Sds = 1.374
    • Total base shear is 1600 kip under ELF loading

My Previous Design process for Diaphragm Design

Let me outline the way I used to design diaphragms

  • Calculate the ELF applied story forces that a program like ETABs/RAM elements produces
    • For our sample building, which I have uploaded to github, we have the following applied diaphragm forces for an ELF type load case
    • Note at story 2, we have an applied force of 34.2kip

 

Story

Elevation

X-Dir

 

ft

kip

Story20

248

164.88

Story19

236

179.202

Story18

224

163.904

Story17

212

149.176

Story16

200

135.029

Story15

188

121.472

Story14

176

108.516

Story13

164

96.173

Story12

152

84.455

Story11

140

73.376

Story10

128

62.951

Story9

116

53.199

Story8

104

44.137

Story7

92

35.79

Story6

80

28.182

Story5

68

21.344

Story4

56

15.314

Story3

44

10.139

Story2

32

34.249

Story1

20

17.783

Base

0

0

 

  • From here, I would then calculate the diaphragm design force according to ASCE 7.
    • For fun, let’s do a quick calc based on the seismic parameters input into the ETABs model. Controlled by Fpx_min and we are checking level (2)
    • Fpx = 0.2*Sds *Wp = 0.2*1.374*(5064kip) = 1392 kip
    • This works out to about 96.67psf over the 120’x120’ level 2 transfer diaphragm
  • Next, I would take the ratio of applied diaphragm force in the ELF case and compare that to the Fpx value, this would be the ratio I would use to amplify my section cut results by to do the design of my chords and collectors, you can maybe start to see the problem.
    • Amplification factor Fpx/Fx = (1392kip)/34.249kip =~ 40.5
  • A small aside, I built this tall 20 story building to demonstrate my point, but when working with smaller buildings that often do not have as explicit of transfer diaphragms, 6-8 stories, built into a hillside for example, the addition of lateral force resisting elements, these ratios are much smaller and seem like they might be reasonable.
  • With the amplification factor, in attempt to capture the minimum diaphragm design force, I amplify my shear force and moment diagram and design my design to resist these amplified forces. You can see that a factor of 40.5 is unreasonable and does not capture what the code is truly trying to capture with minimum diaphragm design forces and higher level mode effects. More on this later.

Sample buildings and iterations with level 2 Transfer Diaphragm

I have uploaded (3) differing ETABs models to github.

  1. The base model with a 24” thick transfer diaphragm

  1. The model with a 12” thick diaphragm and stiffness modifiers to account for cracking
  2. Same model as #1, but with a large hole in the transfer diaphragm

 

 

The new way of designing diaphragms:

Moving forward with diaphragm designs, I will not use this amplification method I outline above anymore. I think this method works for regular buildings, where there is little transfer of forces through diaphragms and for buildings where the lateral force resisting system is “regular”. My definition of regular is that shear force in the lateral force resisting system slowly accumulates on a story, by story basis. Backstay effects and transfer diaphragms are not "regular".

I will note that the sample building I have built, I would define as regular above level 2 and above, the shear force accumulates in the shaft as you move down the building until you hit level 2 and experience the large backstay effect.

The new way of designing diaphragms is running two overall design checks

  1. Running the overall ELF model, reviewing results in the diaphragm with the slicer
  2. Appling a diaphragm design force one level at a time and reviewing the results of the diaphragm with the slice

Please note that these forces need to be amplified for element being design, for example, a lot of collector forces need to be amplified by omega.

My understanding of diaphragm design forces is that they are to capture higher level mode effects where the max diaphragm design force at a specific level would not typically occur in the same assumed manner as the first mode. The first mode and corresponding ELF design forces is the correct way to design the lateral force resisting system and the design of transfer diaphragm forces. In a lot of cases for transfer diaphragms, the typical ELF load distribution will be the worst case diaphragm force.

Fun Sketches

You can see in the 1st mode assumed shape, the lateral load builds up and a majority of the lateral load will have to transferred at the transfer diaphragm to the stiff basement walls if the transfer diaphragm is stiff enough. In the case of the higher level mode deformed shape, the applied loads will typically cancel out as you move from story to story.

This approach is backed up by NEHPR Seismic Design Technical Brief #5, Seismic Design of Composite Steel Deck and Concrete Filled Diaphragms, a few excerpts below

Shear Results

­Onto the fun plots. All plots produced with results from the diaphragm slicer and matplotlib

Notes on the shear plots

  • These are clickable for closer inspection, I realize they are quite tiny. Click to review and zoom
  • You can see big differences in shear forces between the differing models
  • Switching from a 24” thick transfer diaphragm to a 12” diaphragm with stiffness reduction for cracking led to a large decrease in diaphragm shear
    • 1335 kip (12”) / 2380 kip (24” diaphragm) = 0.56
  • Note that this could lead to a negative feedback loop, I need more diaphragm strength, whoops, I have more diaphragm demand.
    • One thing to pay attention to
  • Note that the diaphragm Fpx graph (red line) is tiny in comparison to the other transfer diaphragm forces. This illustrates the pitfalls with my old design method. You live and learn and get better.
  • I was also surprised to see how little impact the large hole had on the shear diagram (black and yellow plot)

Moment Plot

Not much to note here, moment results are in line with what you would expect after reviewing the shear diagrams.

The Takeaway

If you have a transfer diaphragm, be sure to do two diaphragm designs, one based on the overall ELF response and one based on the diaphragm design force applied as individual load case. Even on buildings where diaphragms are not immediately obvious as transfer diaphragms, doing this procedure can reduce your transfer diaphragm forces significantly. Any change in building geometry or the addition of a new lateral force resisting line, consider doing a little extra work of two diaphragm designs and the savings could be well worth it.

Website Updates

I made a few updates to the site, mostly focusing on updating the home page sidebar to have some actual information. The old side bar was just place holder text from the tutorial I found, but the new side bar is populated with the last (3) comments made on the blog. 

Before I dig into the coding to make this happen, I want to make a small aside that my old desktop died that was used to make this site and I have moved onto a new laptop which I have been enjoying. I was bit freaked out when I lost the old desktop due to my poor IT backup practices. I deploy this site using git, but should move the site to github. I need to git this done, it looks like Heroku (the site I deploy to) can accommodate both git and github. 

The process to get the website back up and running on the new machine was pretty easy. Luckily, my SSD in the old desktop was not fried and I was able to copy all of the website files off of the SSD and xfer onto the new computer. I was able to copy all of my environment variables off of the heroku machine and paste them into the computer. After some struggling to get the local variables set up, I was able to begin working on the site again. 

Live Comment Feed

For awhile I wanted to pull a few of the recent comments on the site and have them populate the sidebar like most modern blog sites. Given the popularity of chat gpt, I figured I would give it a go to see if could maybe point me in the right direction. 

ChatGPT - Did it Work?

Not really.  Here is an example of how the interaction I had with chatgpt:

Me: write python to access django comments model and pull the last 3 comments from the database

ChatGPT:
Assuming you have set up your Django project and have a comments app with a Comment
 model, here's an example Python code to access the Comment model and retrieve the
 last three comments from the database:

python

from comments.models import Comment

last_three_comments = Comment.objects.order_by('-id')[:3]

for comment in last_three_comments:
    print(comment.text)

In this code, we import the Comment model from the comments app, and use the objects
 manager to retrieve the last three comments from the database, sorted by the id
 field in descending order (so the most recent comments are first). We then loop
 over the comments and print their text to the console.


Note that the id field may not be the best way to sort comments, depending on how 
your app is set up. You may want to use a created_at or updated_at field instead.

The code that it spat out was correct, but I did not give it enough guidance to properly make this code usable for my specific project. The code produced by chatgpt will extract comments from the database, but this will not in a useable format for rendering into HTML. 

Given that I have not played with Django (package to make the website) in awhile, I forgot a lot of the basics. Once you have retrieved the data you want to be in the webpage, you need to pass this data to a view. This was the part that chatgpt missed and that I had forgotten. After some struggling, I was able to pass this data into my views.py file.

class PostListView(ListView):
    model = Post
    template_name = 'blog/home.html'  # <app>/<model>_<viewtype>.html
    context_object_name = 'posts'
    ordering = ['-date_posted']
    paginate_by = 5
    
    def get_context_data(self, **kwargs):
        context = super(PostListView, self).get_context_data(**kwargs)
        context['last_three_comments']= Comment.objects.order_by('-date_added')[:3]
        #context['last_three_comments']= Post.objects.prefetch_related('comments').all()  
        return context

Setting up get_context_data enables me to pass both post and comment database information into the home.html file.

With a little tweaking to the html file:

{% for comment in last_three_comments %}
     <li class="list-group-item list-group-item-light">{{ comment.name }} on
 {{comment.post.title}} - <a class="article-title" href="{{comment.post.get_absolute_url}}">
{{ comment.body|safe|truncatewords:50}}</a></li>
{% endfor %}

the comments will render in and you get a new linked comment you can click on.

A nice update.

Updatable comments

Next item to tackle, allowing users to update their comments.

If you make a comment and you are the user that made the comment you should see an "Update" button next to your comment now.

The code to make this was pretty easy and I am starting to feel more comfortable working django.

Urls, Views and html:

path('commentupdate/<int:comment_pk>/', CommentUpdateView.as_view(), name='comment-update'),

class CommentUpdateView(LoginRequiredMixin, UpdateView):
    model = Comment
    pk_url_kwarg = "comment_pk"
    fields = ['body']
    success_url = '/'

html
{% if comment.name == user %}
<div>
     <a class = "btn btn-secondary btn-sm mt-1 mb-1" href = "/commentupdate/{{comment.pk}}">Update</a>
</div>

In addition, I added a google tag to the concrete design tool on the site. For the longest time, I thought no one visited this portion of the site, which is probably true, but reviewing the analytics on the site revealed that actually no one had ever visited the site. I realized that I forgot to add a tag to that page. I hope to come back to the concrete design tool soon and document it, I think it is a powerful tool that someone might find useful

Diaphragm Slicer New and Improved

A long time coming... a professional level plugin for ETABs, or at least a whole lot better than the python diaphragm slicer.

User Input

Results

 

This plugin will allow you to slice up your diaphragm in any direction you want, allowing you to see shear and moment along the length of the areas.

User Input

Start Point

This is the point at which you want to start the slicing. Only select an individual point, or the program will show you an error message

Areas

Select any number of objects, ensure all selected area objects share the same Z coordinate.

Input Vector

For slicing in the X direction, input X = 1, Y =0, ensure you input a positive integer. Input field will be limited to numbers and at this moment does allow for negative numbers.

Select Load Case

Pressing the Gather Cases button will retrieve all of the load cases in your current project, be sure to select one from the drop down box, this will be the outputted results from the section cut analysis

Number of Section

Input an integer between 2 and 1000, this will be the number of points that populate shear and moment diagrams

After all of these items are input, click on the run analysis button to view the results.

Reviewing the Results

3 Plots will generate after the program has run, shear (kips), moment (kip*ft), and a plot that shows how the program generated the cuts of your diaphragm for QA of your input.

The plots are all hoverable, allowing you to zoom and review results. In addition, a tabular data table is populated with location (ft), shear and moment being available to be copied and pasted in your favorite spreadsheet.

I have posted the code up on github. I hope to get this addin up on CSI's website in the future. If you have done this before, drop a comment below on how to do this. 

If you want to take this for test run, let me know below. I have yet to try this out in full production, I am sure there are bugs that need to be worked out.

The Coding

Now that the rough documentation is complete, let's dig into the fun stuff.

First thing that strikes me is that python is still freaking awesome! I was able to do this work in python in 233 lines of code and 1 file. This C# addin weighs in at around 1200 lines and 12 files. That's crazy in my opinion! Python is great for whipping up quick ideas.

Where is the variable explorer in Visual Studio Code?!?

Why in the world is there not a built in variable explorer in visual studio code similar to spyder for python. I never realized how great the variable explorer was until you were reviewing many many lines of nested list/array data. I found myself watching a lot of variables in visual studio code, super slow and tedious.

It looks like there might be a way to view large lists of data in visual studio code with a separate addin, but I did not dig into this in depth.

ETABs API

I ran into some trouble with the API when trying to make section cuts with the database tables methods. I had code that worked in ETABs v19, the OG diaphragm slicer, but the code python code would not work in v20 and the C# code I was trying to write would not work in v20 either. Turns out, the database tables headers between v20 and v19 were updated and no longer matched the visual column headers in the section cut tables. After some painful debugging we got this fixed. You can read more about my struggles here.

Matrices in C#

I use matrices in this program to convert back and forth from global coordinates to local coordinates and needed a matrix program if it was available. After some googling, it looked like mathnet.numerics was the most popular matrix package in C#, even above a c# clone of numpy it appears (package used in python to do matrix math). The mathnet package works, but is a bit clunky and I found the documentation hard to read and understand. Eventually, I was able to create a matrix and invert a matrix. Another odd one, it did not support matrix multiplication, I had to do that by hand!

Some of the weird syntax:


 public class GlobalCoordinateSystem
    {
        public List<double> RefPnt { get; set; }
        public List<double> Vector { get; set; }
        public double hyp { get; set; }
        public double[,] R { get; set; }
        public string inverseMatrixText { get; set; }
        public Matrix<double> R_Matrix { get; set; }
        public double[,] R_Inv { get; set; }
        //This is the constructor, redefine the point?
        public GlobalCoordinateSystem(List<double> xyz, List<double> vector)
        {
            RefPnt = xyz;
            hyp = Math.Sqrt((vector[0] * vector[0] + vector[1] * vector[1]));
            Vector = vector;
            R = new double[,] { { vector[0] / hyp, -vector[1] / hyp, 0 }, { vector[1] / hyp, vector[0] / hyp, 0 }, { 0, 0, 1 } };
            R_Matrix = Matrix<double>.Build.DenseOfArray(R);
            R_Inv = R_Matrix.Inverse().ToArray();
        }
    }
}

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

            //the class will now have new attribute of local coordinates point.LocalCoords[0] = the X local coordinate system
            LocalCoords = new List<double>() { globalCoords.R_Inv[0, 0] * part1[0] + globalCoords.R_Inv[0, 1] * part1[1] + globalCoords.R_Inv[0, 2] * part1[2] ,
            globalCoords.R_Inv[1, 0] * part1[0] + globalCoords.R_Inv[1, 1] * part1[1] + globalCoords.R_Inv[1, 2] * part1[2],
            globalCoords.R_Inv[2, 0] * part1[0] + globalCoords.R_Inv[2, 1] * part1[1] + globalCoords.R_Inv[2, 2] * part1[2]};
        }
        public void loc_to_glo(GlobalCoordinateSystem globalCoords)
        {
            //this is the ref point
            double[] part1 = new double[] { X, Y, Z };

            //the class will now have new attribute of local coordinates point.LocalCoords[0] = the X local coordinate system
            GlobalCoords = new List<double>() { (globalCoords.R[0, 0] * X + globalCoords.R[0, 1] * Y + globalCoords.R[0, 2] * Z) + globalCoords.RefPnt[0],
            (globalCoords.R[1, 0] * X + globalCoords.R[1, 1] * Y + globalCoords.R[1, 2] * Z) + globalCoords.RefPnt[1],
            (globalCoords.R[2, 0] * X + globalCoords.R[2, 1] * Y + globalCoords.R[2, 2] * Z) + 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]};
        }

Another point, I need to review why my Z coordinate kept messing up in this process.

C# Plotting

I settled on a plotting package called live charts in C#. This package seemed to be the go-to package back in 2018, but it seems like maybe it has stopped being supported by its developers. Again, documentation was kinda hard to find and when it was able to found, it was hard to understand. More struggling and pain to get to the pretty graphs. I do like the graphs are live, zoomable and interactive. The out-of-the-box microsoft graphs had much less of the interactiveability built into them.

UI Development

I went through a few differing versions of UIs and finally called it good enough where it was. My favorite color is orange, so I wanted to through some orange in the plots, hopefully the plots are not too painful on the eyes.

I also set up a linear gradient brush on the background because why not, it seems like most modern UI's are using color gradients.

A few snips of UI in development

A bit too generic, looks like every other windows form

A bit too much orange

Just right, enough flair to know this guy knows what he's doing, but not too visually distracting:

Eventually I want to get back into this and make rounded buttons and pretty up the tabular data, but I wanted to be done with this project and called it quits at good enough.

Coding for the UI was actually pretty enjoyable in C#, there are a lot of good videos out there on how to make your form look good.

This bit of code makes the linear gradient in the background:

private void Form1_Paint(object send, PaintEventArgs e)
        {
            Graphics mgraphics = e.Graphics;
            Pen pen = new Pen(Color.FromArgb(255, 140, 105), 1);
            Rectangle area = new Rectangle(0, 0, this.Width - 1, this.Height - 1);

            System.Drawing.Drawing2D.LinearGradientBrush lGB2 = new System.Drawing.Drawing2D.LinearGradientBrush(area, Color.FromArgb(255, 255, 255), Color.FromArgb(159, 159, 159), LinearGradientMode.Vertical);
            mgraphics.FillRectangle(lGB2, area);
            mgraphics.DrawRectangle(pen, area);
        }

Please take this for a spin and let me know if you have any feedback!

EDIT 04/19/2023:

The section cut tool is only correct slices in the left right direction! (loading in the X global direction typically) I discovered this after using this on a real project. 

From ETABs documentation:

How is the plane of the section cut defined when drawn in a 3D view?
Expanded Question: When a section cut is drawn in a 3D view, only the X and Y coordinates are provided. How is the section-cut plane defined?

Answer: When using the Draw > Draw Section Cut command, forces are reported in the section-cut coordinate system which is defined by three axes (1,2,Z) as follows:

Section-cut 1 axis is located within the plane parallel to the global X-Y plane, and rotates counterclockwise from the global X axis according to the user-defined parameter Angle (X to 1).
Section-cut 2 axis is also located within the plane parallel to the global X-Y plane, though it is oriented 90° counterclockwise from the section-cut 1 axis.
Section-cut Z axis is parallel to the global Z axis.

I will need to update the code to pull right combination of either F1 or F2. This should not be too difficult to do.

First Previous 1 2 3 4 5 Next Last

Sidebar

Site Info

  • Latest Comments