Table of Contents
Open Table of Contents
Introduction
In this post we will look at how we can apply object oriented programming (OOP) to solve for the second moment of area of common sections. In my guide to section properties we looked at how we can use the principle of superposition to break up complex shapes into smaller ones to make solving for the centroid easier. We also looked at using the parallel axis theorem as a similar method of breaking down complex shapes.
Object oriented program is a style of programming in which we define classes and objects. Classes are like blueprints for objects, and objects are instances of classes. This works well for engineering problems since we often have something tangible that we want to represent.
In this blog we will work from the bottom up first defining the classes for a basic rectangle and then using that class to construct more complex shapes like an I Section.
Our code will be written in Javascript and can be run from any browser.
Defining the Rectangle Class
class Rectangle {
constructor(d, b) {
this.d = d;
this.b = b;
this.A = this.b * this.d;
}
}
To construct a class we simply use class Rectangle { }
and then define the constructor function. The constructor function is a special function that is called when we create a new object from the class. In the constructor function we define the properties of the object. By convention we capitalise the name of the class.
We use the this
keyword to refer to the properties of the object. In this case we have defined the properties d
and b
which are the depth and breadth of the rectangle. We have also defined the property A
which is the area of the rectangle.
If we were to construct new methods in the class then we could access these properties using the this
keyword.
class Rectangle {
constructor(d, b) {
this.d = d;
this.b = b;
this.A = this.b * this.d;
}
logProperties() {
console.log(`Depth: ${this.d}`);
console.log(`Breadth: ${this.b}`);
console.log(`Area: ${this.A}`);
}
}
We can use our class by creating a new object from it.
let rect1 = new Rectangle(10, 20);
let rect2 = new Rectangle(5, 10);
rect1.logProperties();
// Depth: 10
// Breadth: 20
// Area: 200
rect2.logProperties();
// Depth: 5
// Breadth: 10
// Area: 50
We can see how this code is useful since we can create multiple different rectangles from the same class.
Since we are interested in the second moment of area of the rectangle we will also define the properties Ix
and Iy
which are the second moment of area about the x and y axes respectively. We can use the common formula for the second moment of area about a rectangles centroid which we derrived in the guide to section properties.
class Rectangle {
constructor(d, b) {
this.d = d;
this.b = b;
this.A = this.b * this.d;
this.Ix = this.b * this.d ** 3 / 12;
this.Iy = this.b ** 3 * this.d / 12;
}
}
Defining the general composite class
Next we want to define a class which can calculate the properties of a section which contains any number of rectangles. We will call this class Composite
.
Since we will have rectangles at different (x,y) coordinates in our Composite
section we will also need to track the position of each rectangle. We will update the Rectangle
class to also store the centroid of each rectangle. We will default these values to 0,0 so that if a user just wants to calculate the properties of a single rectangle they can do so without having to specify the centroid.
class Rectangle {
constructor(d, b, cx = 0, cy = 0) {
this.cx = cx;
this.cy = cy;
this.d = d;
this.b = b;
this.A = this.b * this.d;
this.Ix = this.b * this.d ** 3 / 12;
this.Iy = this.b ** 3 * this.d / 12;
}
}
I will define the Composite
class constructor to take a list of rectangles, and using the principle of superposition we can define a simple method that calculates the total area of the section. (Note that we ignore the overlap of the rectangles).
class Composite {
constructor(rectangles) {
this.rectangles = rectangles;
}
calcArea() {
let area = 0;
this.rectangles.forEach(rect => {
area += rect.A
})
return area;
}
}
We can update the class in a very similar method using the parallel axis theorem and superposition to calculate the centroid and second moment of area for the composite section.
class Composite {
constructor(rectangles) {
this.rectangles = rectangles;
}
calcArea() {
let area = 0;
this.rectangles.forEach(rect => {
area += rect.A
})
return area;
}
calcCentroid() {
// get the area of the composite section
let A = this.calcArea();
let Ay = 0;
let Ax = 0;
this.rectangles.forEach(rect => {
Ay += rect.A * rect.cy;
Ax += rect.A * rect.cx;
})
// deal with potential divide by zero error
if (A == 0){
return [0, 0]
} else {
return [Ax / A, Ay / A]
}
}
calcSecondMoments() {
let [cx, cy] = this.calcCentroid();
let Iy = 0;
let Ix = 0;
this.rectangles.forEach(rect => {
Iy += (rect.A * (rect.cx - cx) ** 2 + rect.Iy);
Ix += (rect.A * (rect.cy - cy) ** 2 + rect.Ix);
})
return [Ix, Iy]
}
logProperties() {
console.log(`Area: ${this.calcArea()}`);
console.log(`Centroid: ${this.calcCentroid()}`);
console.log(`Second Moment of Area: ${this.calcSecondMoments()}`);
}
}
We can for example create the very simple composite section from the guide to section properties.
let r1 = new Rectangle(1,1,0.5,0.5);
let r2 = new Rectangle(1,1,0.5,1.5);
let r3 = new Rectangle(1,1,1.5,1);
let r4 = new Rectangle(1,1,2.5,1);
let composite = new Composite([r1, r2, r3, r4]);
composite.logProperties();
// Area: 4
// Centroid: 1.25, 1
// Second Moment of Area: 0.833,3.083
Awesome! Looks like we have successfully created a class that can calculate the properties for a composite section.
Applying the composite class to an I Section
We have a general method for calculating the properties of a composite section (made of rectangles). A useful upgrade now would to be able to mould our general class so that it is more specific to something common like an I Section.
The way we will do this is by creating a new class ISection
which extends the Composite
class. This means that the ISection
class will have all the methods of the Composite
class but we can also add new methods to the ISection
class. In our case we wont actually add any new methods, we already have everything we need, we will just update the constructor to take the dimensions of an I Section and pass the rectangles that make up the I Section through to the Composite
class.
We will give the class its own constructor which takes:
- d: the overall depth of the I Section
- b: the overall breadth of the I Section
- tf: the thickness of the flange
- tw: the thickness of the web
We can then construct 3 rectangle objects for the top flange, bottom flange and web of the I Section.
Once we have all these we use the super
keyword to call the constructor of the Composite
class and pass through the list of shapes that we want this composite section to be made up of.
class Isection extends Composite {
constructor(d, b, tf, tw) {
let top_flange = new Rectangle(tf, b, b / 2, d - tf / 2)
let bot_flange = new Rectangle(tf, b, b / 2, tf / 2)
let web = new Rectangle(d - 2 * tf, tw, b / 2, d / 2)
super([top_flange, bot_flange, web])
}
}
With that we have everything we need to calculate the properties of an I Section. Lets test it out on a 150 UB 18.0 I Section which has:
- Depth: 155 mm
- Breadth: 75 mm
- Flange Thickness: 9.5 mm
- Web Thickness: 6.0 mm
let ub150 = new Isection(155, 75, 9.5, 6)
ub150.logProperties();
// Area: 2241
// Centroid: 37.5,77.5
// Second Moment of Area: 8810346.75,670416.75
We can see that the values are a conservative estimate within 5% of the actual property values which are given on beamdimensions
Property | Calculated Value | Actual Value | Percentage Difference |
---|---|---|---|
Area | 2241 | 2300 | 2.6 % |
Centroid (X) | 37.5 | 37.5 | 0.0 % |
Centroid (Y) | 77.5 | 77.5 | 0.0 % |
Ix | 8810346.75 | 9050000 | 2.7 % |
Iy | 670416.75 | 672000 | 0.3 % |
The reason for this difference is the fillet radius. Since all the fillet radius are quite close to the vertical plane of symetry they do not have much impact on Iy, and we can see there is a more significant impact on Ix.
All the values we calculated do ere on the conservative side regardless which makes these values acceptable to use in design.
If we want to be more accurate, in fact entirely accurate we can update our object oriented approach to include the fillet radius.
Using this post and the guide to section properties the reader should have enough information to be able to construct such code as an excerise of their own. I have personally written this code but will not share it since it is a good test of the readers knowledge and understanding if they can write it themselves.
Conclusion
Object oriented programming approaches are often extremely useful in engineering problems since we often have tangible objects that we want to represent.
In this post we have used some very simple code and concepts which save us from writing out annoyingly long analytical equations. Using an understanding of the mechanics of solids and some fundamental object oriented programming we have created some code which can be used in real world applications.