Mark DiVecchio's O-Gauge Train Layouts

1992 Layout Page

2006 Layout Page

2009 Layout Page

P&LE Postcards by Howard Fogg 

Plasticville Buildings

Portable Layout Page

Train Clubs

Bing Track

Remote Train Control Program

YouTube Channel

OOK Radio Support

Technical Videos


More RTC Videos

ADPCM - Playing clips from .mth sound files

P&LE McKees Rocks Locomotive Shop
3D Printer Project

White Tower Restaurant
3D Printer Project

RFID Train Detection


3D Prints for my Train Layout

This Page last updated on .

Here are some of the 3D prints that I did for my train layout. Some were developed by me and some were found on-line.


P&LE McKees Rocks Locomotive Shop

This 3D print has its own web page - click here.

White Tower Restaurant

This 3D print has its own web page - click here.

New Sign for the Plasticville Frosty Bar

I like Plasticville but the main town on my layout is not Plasticville but is Aliquippa, PA - my hometown. And in Aliquippa, we had a Dairy Queen.
The sign is available on Thingiverse where you can customize it and create an stl file which can be sent to one of the on-line 3D print shops : https://www.thingiverse.com/thing:3159254
I used my 3D printer to make a new sign for the Frosty Bar.



Original Sign. I got out my calipers and measured each feature on the sign.

I did the measurements in millimeters since that is the standard unit of measurement used in the 3D modeling program I used. After doing a few, it was clear that Bachmann built the original molds using English measurement. Every measurement was coming out the MKS equivalent of 1/4 inch, 1/8 inch, 3/16 inch, etc.

There are many programs that can be used for 3D modeling. For this project, I used the OpenSCAD program.

I really like this method of modeling because it is programmatic. I used it for my P&LE Locomotive Shop which has thousands of individual bricks. I didn't have to construct each one. I used computer code to do one and then repeated it over and over in a code loop.

For this sign, I created the OpenSCAD code in about an hour - though it took a few tweaks and several test prints to get the results that I wanted.


Here is screen capture of the sign by OpenSCAD. Fonts were a problem especially for the "Frosty Bar" font. I found that the town name was pretty close to "Arial" but the Frosty Bar sign did not match any font that I had available or any font that I could find. I ended up choosing the font "Pump Demi Bold LET". I adjusted the "spacing" parameter to try to match the original sign as well as I could.

Let me know if you have any information about the font used on the "Frosty Bar" sign.

In OpenSCAD, you create 2D objects which you extrude into 3 dimensions or you can create 3D objects directly. I created the basic sign shape from a polygon which I then extruded. I used the "offset" command to make the small fillets at the left and right edges of the sign. To create the "inner" fillets on the left and right inside corners I used  a cylinder subtracted from a cube. Look at the "difference" command in the code.

The color in this rendering is false. I ended up painting the sign.

This step produces an ".stl" file which is used in the next step.
Here is a listing of the Plasticville Frosty Bar Sign.scad file:

//
// Customizable Plasticville Frosty Bar Sign.scad
// Mark DiVecchio
// July 2018 V1.0
// Original development using OpenSCAD 2017.01.20
//
// This SCAD script is licensed under a
// Creative Commons Attribution-NonCommercial 3.0 Unported License.
//
/*
My web page: http://www.silogic.com/trains/layout.html
*/
// http://www.silogic.com/trains/layout.html
//
$fn=128 * 1;
//
// CUSTOMIZING
// New Frosty Bar Name
Name = "DAIRY QUEEN";
// New Name Font (On Line Fonts: fonts.google.com)
NameFont = "Pump Demi Bold LET";
// Letter spacing in Bar Name
NameSpacing = 1.1;
// New Town Name
Town = "ALIQUIPPA";
// Town Name Font (On Line Fonts: fonts.google.com)
TownFont = "Arial";
// Letter spacing in Town Name
TownSpacing = 1.3;
// Width of base of sign (enter in mm)
Width = 114;
// Height of base of sign (enter in mm)
Height = 3.14;
// Width of town name portion of sign (enter in mm)
WidthName = 90.04;
// Height of name portion of sign (enter in mm)
HeightName = 6.45;
// Thickness of sign (enter in mm)
Thickness = 1.5;
// Thickness of Letters of the name portion of sign (enter in mm)
ThicknessNameLetters = 2.29;
// Height of Frosty Bar Letters (enter in mm)
HeightFBLetters = 8.25;
// Width of Frosty Bar Letters (enter in mm)
WidthFBLetters = 6.41;
// Height of Town Name letters (enter in mm)
HeightTNLetters = 3.77;
// Width of Town Name Letters (enter in mm)
WidthTNLetters = 4.03;

print_part();

/////////////
// Modules //
/////////////
module print_part() {
sign();
}
module sign () {
// Base (Width * Height x Thickness)
color("peachpuff")
linear_extrude(Thickness) {
offset(r = 0.5) {
polygon(points=[
[0 + 0.5,0 + 0.5],
[0 + 0.5, Height - 0.5],
[Width - 1,Height - 0.5],
[Width - 1, 0 + 0.5]
]);
}
}
// Middle (WidthName x HeightName x Thickness)
color("peachpuff")
linear_extrude(Thickness) {
wval = 4;
offset(r = wval/2) {
polygon(points=[
[((Width - WidthName)/2) + (wval/2),0 + (wval/2)],
[((Width - WidthName)/2) + (wval/2), Height + HeightName - (wval/2)],
[(WidthName + (Width - WidthName)/2) - (wval/2),Height + HeightName - (wval/2)],
[(WidthName + (Width - WidthName)/2) - (wval/2), 0 + (wval/2)]
]);
}
}

// inner fillet - left
color("peachpuff")
difference() {
translate([((Width - WidthName)/2)-2,Height - 2,0])
cube(size = [4, 4, Thickness], center = false);
translate([((Width - WidthName)/2)-2,Height + 2,-0.5])
cylinder(h = Thickness * 2, r=2, center = false);
}

// inner fillet - right
color("peachpuff")
difference() {
translate([(WidthName + (Width - WidthName)/2)-2,Height - 2,0])
cube(size = [4, 4, Thickness], center = false);
translate([(WidthName + (Width - WidthName)/2)+2,Height + 2, -0.5])
cylinder(h = Thickness * 2, r=2, center = false);
}

// Name of Frosty Bar (letters are HeightFBLetters x WidthFBLetters)
color("peachpuff")
translate([Width/2, Height + HeightName, 0])
linear_extrude(Thickness)
text(Name, font=NameFont, size=HeightFBLetters, spacing=NameSpacing, halign="center");

// Name of town (red) (letters are HeightTNLetters x WidthTNLetters)
color("red")
translate([Width/2, Height + ((HeightName - HeightTNLetters)/2), 0])
linear_extrude(ThicknessNameLetters)
text(Town, font=str(TownFont, ":style=Bold"), size=HeightTNLetters, spacing=TownSpacing, halign="center");
}



The slicer program that I use with my Original Prusa i3 MK2s is "Slic3r". A customized version of that program is provided by Prusa. Slic3r reads the *.stl file created by OpenSCAD and slices the design. Output is a "*.gcode" file which is then sent to the 3D printer.

I used the default slicer setting in Slic3r provided by Prusa. It is called "0.15mm OPTIMAL".


Here is the sign as printed. Still on the print bed. I used white PLA because I had it. Since the sign was going to be painted, it didn't matter too much what color PLA was used. Took about an hour to print.


Here is a close up of the sign. You can see the lines of PLA as laid down by the printer. This type of printing does not produce the nice smooth results of the injection molding of the original Bachmann products. Painting helps hide these lines. Other people talk about sanding the object with 200 to 3000 grit sandpaper to remove some of the lines but I've not tried that.


Even though I used white PLA, I still painted the sign white. That paint (from WalMart) helped smooth out the surface. I painted the tops of the red letters of Aliquippa.


Here is the sign in place on the Frosty Bar in the park on my layout (now christened Dairy Queen).



New Sign for the Plasticville Frosty Bar V2

This is version 2 of my Plasticville replacement sign.

The version 1 sign shown above is mostly of the same shape and format of the original Frosty Bar Sign. That sign used a font that was only an approximation of the actual font used on the actual sign. This sign is more true to the actual Dairy Queen sign. I modified my OpenSCAD program to use the "surface" command. That command is extremely powerful.

I found a photo of an actual Dairy Queen sign. Then I found a photo of the words "DAIRY QUEEN" in the correct font. Then I found a photo of a Dairy Queen ice cream cone.

I used those photos along with the surface command to make a pretty reasonable representation in OpenSCAD of an actual Dairy Queen sign.

I rendered it and then input it into the Prusa slicer. I then laid the sign flat on the printbed. I had to use supports under the cone since it does not touch the printbed.

Along with the OpenSCAD code, you need the files "DQ_1950s_logo - edited.png" and "Dairy Queen Ice Cream Cone Sign - edited.png" (all available below). I edited each of those images to be black and white which work perfectly with the "surface" command in OpenSCAD.

I printed in white PLA but you can use any color as the sign will have to be painted in any case.


This is a photo of the new sign on my layout.

Prusa Slicer

On the printbed. You can see the supports generated underneath the ice cream code.

There is one really nice model of a Dairy Queen on the HO layout of the North County Model Railroad Society (NCMRS) in Oceanside, CA.

There is a photo of a Dairy Queen sign taken in Ottawa. 
Here is a listing of the Plasticville Frosty Bar Sign - Correct Font  and Ice Cream Cone.scad file:

//
// Customizable Plasticville Frosty Bar Sign - Correct Font and Ice Cream Cone.scad
// Mark DiVecchio
// October 2021 V2.0
// Original development using OpenSCAD 2017.01.20
//
// This SCAD script is licensed under a
// Creative Commons Attribution-NonCommercial 3.0 Unported License.
//
/*
My web page: http://www.silogic.com/trains/layout.html
*/
// http://www.silogic.com/trains/layout.html
//
$fn=128 * 1;
//
// CUSTOMIZING
// New Town Name
Town = "ALIQUIPPA";
// Town Name Font (On Line Fonts: fonts.google.com)
TownFont = "Arial";
// Letter spacing in Town Name
TownSpacing = 1.3;
//
// Width of base of sign (enter in mm)
Width = 114;
// Height of base of sign (enter in mm)
Height = 3.14;
// Width of town name portion of sign (enter in mm)
WidthName = 90.04;
// Height of name portion of sign (enter in mm)
HeightName = 21.45;
// Thickness of sign (enter in mm)
Thickness = 1.5;
// Thickness of Letters of the name portion of sign (enter in mm)
ThicknessNameLetters = 2.29;
// Height of Town Name letters (enter in mm)
HeightTNLetters = 3.77;
// Width of Town Name Letters (enter in mm)
WidthTNLetters = 4.03;

print_part();

/////////////
// Modules //
/////////////
module print_part() {
sign();
}
module sign () {
// Base (Width * Height x Thickness)
color("peachpuff")
linear_extrude(Thickness) {
offset(r = 0.5) {
polygon(points=[
[0 + 0.5,0 + 0.5],
[0 + 0.5, Height - 0.5],
[Width - 1,Height - 0.5],
[Width - 1, 0 + 0.5]
]);
}
}
// Middle (WidthName x HeightName x Thickness)
color("peachpuff")
linear_extrude(Thickness) {
wval = 4;
offset(r = wval/2) {
polygon(points=[
[((Width - WidthName)/2) + (wval/2),0 + (wval/2)],
[((Width - WidthName)/2) + (wval/2), Height + HeightName - (wval/2)],
[(WidthName + (Width - WidthName)/2) - (wval/2),Height + HeightName - (wval/2)],
[(WidthName + (Width - WidthName)/2) - (wval/2), 0 + (wval/2)]
]);
}
}

// inner fillet - left
color("peachpuff")
difference() {
translate([((Width - WidthName)/2)-2,Height - 2,0])
cube(size = [4, 4, Thickness], center = false);
translate([((Width - WidthName)/2)-2,Height + 2,-0.5])
cylinder(h = Thickness * 2, r=2, center = false);
}

// inner fillet - right
color("peachpuff")
difference() {
translate([(WidthName + (Width - WidthName)/2)-2,Height - 2,0])
cube(size = [4, 4, Thickness], center = false);
translate([(WidthName + (Width - WidthName)/2)+2,Height + 2, -0.5])
cylinder(h = Thickness * 2, r=2, center = false);
}

//-----------------------------------------------------
translate([60, 17, -1.1]) {
// Words "DAIRY QUEEN"
difference() {
translate([0,0,5])
scale([0.1, 0.1, 0.025])
surface(file = "DQ_1950s_logo - edited.png", center = true, invert = true);
translate([0,0,2.5])
cube([100,100,0.2],center=true);
}
// Ice Cream Cone
difference() {
translate([-50,0,5])
rotate([0,0,30])
scale([0.1, 0.1, 0.025])
surface(file = "Dairy Queen Ice Cream Cone Sign - edited.png", center = true, invert = true);
translate([0,0,2.5])
cube([150,150,0.2],center=true);
}
}
//-----------------------------------------------------

// Name of town (red) (letters are HeightTNLetters x WidthTNLetters)
color("red")
translate([Width/2, Height + ((HeightName - HeightTNLetters)/6), 0])
linear_extrude(ThicknessNameLetters)
text(Town, font=str(TownFont, ":style=Bold"), size=HeightTNLetters, spacing=TownSpacing, halign="center");
}




DQ_1950s_logo - edited.png

Needed for the OpenSCAD code.


Dairy Queen Ice Cream Cone Sign - edited.png

Needed for the OpenSCAD code.

This black and white photo is from the 1954 yearbook of my hometown, Aliquippa, PA. This DQ was a popular place in the 50's and 60's. The building is still there but now houses an architect. I was 6 years old when this picture was taken, so I'm pretty sure that I and not in it.


New Sign for the Plasticville Turnpike

Once I had the new Frosty Bar Sign done, it was a quick job to make a new sign for the Plasticville Turnpike.
The sign is available on Thingiverse where you can customize it and create an stl file which can be sent to one of the on-line 3D print shops : https://www.thingiverse.com/thing:3189546

Since my layout represents the Pittsburgh & Lake Erie between McKees Rocks and Youngstown, I wanted a turnpike entrance that made sense. The Pennsylvania Turnpike and its Beaver Valley Interchange are the nearest to the P&LE track.

So with the knowledge gained by doing the new Dairy Queen sign, I again used OpenSCAD and wrote a program to create a new turnpike sign. The first step was to measure each piece of the sign. Then I had to pick fonts for the letters. Again, not knowing what fonts Bachmann used, I looked for something close. This time I looked on "Google Fonts". You can google that. I found a font called "Bungee" and used that for the interchange name. For the turnpike name, I stuck with "Arial".

The development and printing steps were the same as I used on the Dairy Queen sign. Look at that section of this web page for the details.


Here is the sign as it appears in OpenSCAD. The colors are false.

Here is the print, still on the print bed.
I printed with blue PLA to save some painting. The blue does not exactly match the blue of the turnpike buildings. But close enough for now.

I printed at 100% fill with 3 perimeters - otherwise using the Prusa defaults for "Original Prusa i3 MK2" and "0.15 mm OPTIMAL" print settings.
I put two copies of the sign on the print bed since two are needed for the Turnpike.
Took about 3 hours to print both signs.
Here is a listing of the Plasticville Turnpike Sign.scad file:

//
// Customizable Plasticville Turnpike Sign.scad
// Mark DiVecchio
// October 2018 V2.0
// Original development using OpenSCAD 2017.01.20
//
// This SCAD script is licensed under a
// Creative Commons Attribution-NonCommercial 3.0 Unported License.
//
/*
My web page: http://www.silogic.com/trains/layout.html
*/
// http://www.silogic.com/trains/layout.html
//
$fn=128 * 1;
//
// CUSTOMIZING
// New Interchange Name
INT = "BEAVER VALLEY INTERCHANGE";
// New Interchange Name Font (On Line Fonts: fonts.google.com)
INTFont = "Bungee";
// Letter spacing in Interchange Name
INTSpacing = 1.0;
// New Turnpike Name
Pike = "PENNSYLVANIA TURNPIKE";
// Turnpike Name Font (On Line Fonts: fonts.google.com)
PikeFont = "Arial";
// Letter spacing in Turnpike Name
TPSpacing = 1.1;
// Width of base of sign 6 11/16" (enter in mm)
Width = (6 + 11/16) * 25.4;
// Height of base of sign 0.0875"(enter in mm)
Height = (0.0875) * 25.4;
// Thickness of sign 0.1" (enter in mm)
ThicknessINTLetters = (0.1) * 25.4;
// Spacing to center horizontal brace (enter in mm)
BraceOffset = (0.2665 - 0.08) * 25.4;
// Height of bottom portion of sign (enter in mm)
BottomHeight = (1.035) * 25.4;
// Height of top horizonal Beam (enter in mm)
TopBeamHeight = (0.2) * 25.4;
// Spacing to top horizontal Beam (enter in mm)
TopBeamOffset = (BottomHeight - TopBeamHeight - 1.75);
// Left Center Bar Offset
LCBarOffset = (Height + (1.91 * 25.4));
// Right Center Bar Offset
RCBarOffset = (Width - LCBarOffset - Height);
// Width of top hat
TopWidth = (7 + 11/16) * 25.4;
// Height of top hat
TopHeight = (0.0685) * 25.4;
// Thickness of top hat
TopThickness = (0.15) * 25.4;

//
// Width of turnpike name portion of sign (enter in mm)
WidthName = 90.04;
// Height of turnpike portion of sign (enter in mm)
HeightName = 6.45;

// Thickness of Letters of the turnpike portion of sign (enter in mm)
ThicknessTPLetters = (0.11 * 25.4);
// Height of interchange Letters (enter in mm)
HeightINTLetters = 8.25;
// Width of interchange Letters (enter in mm)
WidthINTLetters = 6.41;
// Height of Turnpike Name letters(enter in mm)
HeightTPLetters = (0.2665 * 25.4);
// Width of Turnpike Name Letters (enter in mm)
WidthTPLetters = 3.5;

print_part();

/////////////
// Modules //
/////////////
module print_part() {
sign();
}
module sign () {
// right Riser
color("blue") translate([Width - Height - 0.5, 0.5, 0])
cube([Height, BottomHeight - Height, ThicknessINTLetters - 0.5]);
// left Riser
color("blue") translate([0, 0.5, 0])
cube([Height, BottomHeight - Height, ThicknessINTLetters - 0.5]);
// left center Riser
color("blue") translate([LCBarOffset, BraceOffset + Height, 0])
cube([Height, BottomHeight - BraceOffset - Height - Height + 0.5, ThicknessINTLetters - 0.5]);
// right center Riser
color("blue") translate([RCBarOffset, BraceOffset + Height, 0])
cube([Height, BottomHeight - BraceOffset - Height - Height + 0.5, ThicknessINTLetters - 0.5]);

// Top Hat
color("blue")
translate([(TopWidth - Width)/-2, BottomHeight, 0])
rotate([90, 0, 0])
linear_extrude(TopHeight) {
offset(r = 0.5) {
polygon(points=[
[0 + 0.5,0 + 0.5],
[0 + 0.5, TopThickness - 0.5],
[TopWidth - 1,TopThickness - 0.5],
[TopWidth - 1, 0 + 0.5]
]);
}
}
// Bottom Beam
// Base (Width * Height * Thickness) with a fillet
color("blue")
linear_extrude(ThicknessINTLetters - 0.5) {
offset(r = 0.5) {
polygon(points=[
[0 + 0.5,0 + 0.5],
[0 + 0.5, Height - 0.5],
[Width - 1,Height - 0.5],
[Width - 1, 0 + 0.5]
]);
}
}
// Middle Beam
// Base (Width * Height * Thickness) with a fillet and translate
color("blue")
translate([0, BraceOffset + Height, 0])
linear_extrude(ThicknessINTLetters - 0.5) {
offset(r = 0.5) {
polygon(points=[
[0 + 0.5,0 + 0.5],
[0 + 0.5, Height - 0.5],
[Width - 1,Height - 0.5],
[Width - 1, 0 + 0.5]
]);
}
}
// Top Beam
// Base (Width * TopBeamHeight * Thickness) with a fillet and translate
color("blue")
translate([0, TopBeamOffset, 0])
linear_extrude(ThicknessINTLetters - 0.5) {
offset(r = 0.5) {
polygon(points=[
[0 + 0.5,0 + 0.5],
[0 + 0.5, TopBeamHeight - 0.5],
[Width - 1,TopBeamHeight - 0.5],
[Width - 1, 0 + 0.5]
]);
}
}

// Name of Interchange (letters are HeightINTLetters x WidthINTLetters)
color("blue")
translate([Width/2, BottomHeight, 0])
linear_extrude(ThicknessINTLetters)
text(INT, font=INTFont, size=HeightINTLetters, spacing=INTSpacing, halign="center");

// Name of Turnpike (blue) (letters are HeightTPLetters x WidthTPLetters)
color("white")
translate([Width/2, Height/2, 0])
linear_extrude(ThicknessTPLetters)
text(Pike, font=str(PikeFont, ":style=Bold"), size=HeightTPLetters, spacing=TPSpacing, halign="center");
}

I painted the turnpike name white to match what Bachmann did on the original turnpike.

Here is the updated Pennsylvania Turnpike sign at the Beaver Valley Interchange, about 20 miles from my childhood home in Aliquippa, PA.

Here it is on my layout.



Mini Trash Can

Found on Thingiverse.com  by 3D-Fuel.



I printed this for my O-gauge layout. Reduced in size by 25%. It comes out with pretty thin walls but I had Slic3r watch out for thin perimeters/shells/walls. I set the layers to 0.1mm and it printed pretty well on my Original Prusa i3 MK2s. Printed in black PLA, Bottom spray painted a grayish color.

Parts for my track cleaning car

Fuel Tank (Reservoir d eau)
Found on Thingiverse.com by JEBILO

Diesel Engine  60%
Found on Thingiverse.com by lefab.

Basic car from North East Trains.



Dumpster

Found on Thingiverse.com by Simonarri.



For my O gauge layout, I printed this at 75%, 2 top/bottom/perimeter layers, 10% fill at 0.2mm. I used a piece of wire for the hinge. Filled with scraps of paper.

Picnic Table

Found on Thingiverse.com by PrettySmallThings.
Found on Thingiverse.com by bnoggle.



Grade Crossing

My layout, which uses O gauge tubular track never had very realistic grade crossings since the track is a scale 3 feet(!) high.
The grade crossing is available on Thingiverse where you can customize it and create an stl file which can be sent to one of the on-line 3D print shops.
The curved version is at  : https://www.thingiverse.com/thing:2832224
and the straight version is at: https://www.thingiverse.com/thing:3193426

I used OpenSCAD again because of its ability to be customized for different radius curves. There are two OpenSCAD programs, one  for curved track where you can select four different radii and one for straight track.

Here is a listing of the Grade Crossing Curved.scad file:

//
// Customizable Curved Grade Crossing - Lionel O Tubular Track
// Mark DiVecchio
// March 2018
// Original development using OpenSCAD 2017.01.20
//
// This SCAD script is licensed under a
// Creative Commons Attribution-NonCommercial 3.0 Unported License.
//
// V1.0 - original release
// V2.0 - adds ramps
//
// http://www.silogic.com/trains/layout.html
//
// in slicer, rotate y = 180 deg, rotate z = 45 deg (to get long print lines)
// use 2 bottom layers, 0 top layers, rectilinear bottom layers
//
$fn=200*1;
//
// CUSTOMIZING
//

/* Configuration */
// Length of the crossing in inches
Piece_Length = 6; // [3:0.5:10]
// Diameters were taken from measurements of circles
// using the RR-Track program. [O-31, O-42, O-54, O-72]
// in inches from center rail to center rail
// Track Diameter
Diameter = 72.5; //[28.6:O-31, 40.75:O-42, 53.3:O-54, 72.5:O-72]
// Width of each crossing segment in inches (Leave enough space for the wheel flanges)
Top_Width = 0.4;
// Number of sections to break the crossing into
Sections_per_Piece = 5; //[1:10]
// Create grade crossing or ramp (will invert the ramps for printing)?
To_Print = "grade"; // [grade,ramp]
// Ramp Height in inches
Ramp_Height = 0.717;
// Ramp Length in inches
Ramp_Length = 3; //[2:10]
// Ramp Thickness in inches
Ramp_Thickness = 0.1; //[0.1,0.15,0.2,0.25]//
//
/* [Hidden] */
// Bottom Width
Bottom_Width = Top_Width - 0.25;
// Height
Height = 0.319;
// Ledge
Ledge = 0.100;
// Conversion inches to millimeters
inch=25.4;
// Board Spacing slot
Board_Space = 0.02;

print_part();

/////////////
// Modules //
/////////////

module print_part() {

translate([ -(Diameter * inch)/2, 0, 0 ])
{
if (To_Print == "grade") difference() {
union () {
translate([0,0,0])
InnerCurvedCrossing(Diameter);
translate([Board_Space * inch,0,0])
OuterCurvedCrossing(Diameter);
translate([(Board_Space * 1) * -1 * inch,0,0])
Inner2CurvedCrossing(Diameter);
translate([(Board_Space * 2) * 1 * inch,0,0])
Outer2CurvedCrossing(Diameter);
}

union () {
for (chunks = [1 : Sections_per_Piece]) {
rotate([0,0,(Piece_Length* chunks/Sections_per_Piece) / (2 * 3.14159 * (Diameter/2)) * 360]) Slots();
}
}
}
if (To_Print == "ramp") {
rotate([180, 0, 0]) {
translate([0,0,0])
InnerCurvedRamp(Diameter);
translate([0,0,0])
OuterCurvedRamp(Diameter);
}
}
if (To_Print == "grade") {
%translate([0,0,0])
InnerCurvedRamp(Diameter);
%translate([0,0,0])
OuterCurvedRamp(Diameter);
}
}
}

module InnerCurvedRamp(D) {
translate([0,, 0, -(Ramp_Height - Height) * inch])
rotate_extrude(angle=(Piece_Length / (2 * 3.14159 * (D/2))) * 360)
translate([(D/2 - (2 *Top_Width) - (2 * Board_Space) - Ramp_Length) * inch, 0, 0])
rotate([0, 0, To_Print=="ramp" ? -atan(Ramp_Height/Ramp_Length): 0])
polygon([[0,0],
[Ramp_Length * inch, Ramp_Height * inch],
[Ramp_Length * inch, (Ramp_Height - Ramp_Thickness) * inch],
[(Ramp_Length - 0.5) * inch, (Ramp_Height - Ramp_Thickness - (0.5) * (Ramp_Height / Ramp_Length)) * inch],
[(Ramp_Length - 0.5) * inch, 0],
[(Ramp_Length - 0.5 - Ramp_Thickness) * inch, 0],
[(Ramp_Length - 0.5 - Ramp_Thickness) * inch, (Ramp_Height - Ramp_Thickness - (0.5 + Ramp_Thickness) * (Ramp_Height / Ramp_Length)) * inch],
[(Ramp_Thickness * Ramp_Length / Ramp_Height) * inch, 0]
]);
}

module OuterCurvedRamp(D) {
translate([0,, 0, -(Ramp_Height - Height) * inch])
rotate_extrude(angle=(Piece_Length / (2 * 3.14159 * (D/2))) * 360)
translate([(D/2 + (2 *Top_Width) + (3 * Board_Space) + Ramp_Length) * inch, 0, 0])
rotate([0,180,0])
rotate([0, 0, To_Print =="ramp" ? -atan(Ramp_Height/Ramp_Length): 0])
polygon([[0,0],
[Ramp_Length * inch, Ramp_Height * inch],
[Ramp_Length * inch, (Ramp_Height - Ramp_Thickness) * inch],
[(Ramp_Length - 0.5) * inch, (Ramp_Height - Ramp_Thickness - (0.5) * (Ramp_Height / Ramp_Length)) * inch],
[(Ramp_Length - 0.5) * inch, 0],
[(Ramp_Length - 0.5 - Ramp_Thickness) * inch, 0],
[(Ramp_Length - 0.5 - Ramp_Thickness) * inch, (Ramp_Height - Ramp_Thickness - (0.5 + Ramp_Thickness) * (Ramp_Height / Ramp_Length)) * inch],
[(Ramp_Thickness * Ramp_Length / Ramp_Height) * inch, 0]
]);
}


module InnerCurvedCrossing(D) {
// Main Inner curved body
echo("Inner: angle ", (Piece_Length / (2 * 3.14159 * (D/2))) * 360);
rotate_extrude(angle=(Piece_Length / (2 * 3.14159 * (D/2))) * 360)
translate([(D/2 - Top_Width) * inch,0,0])
rotate([0, 0, 0])
polygon([[0,0], // 1
[0,(Height) * inch], // 2
[((Top_Width/3) - Board_Space)* inch,(Height) * inch], // a
[((Top_Width/3) - Board_Space)* inch,(Height - Board_Space) * inch], // b
[((Top_Width/3))* inch,(Height - Board_Space) * inch], // c
[((Top_Width/3))* inch,(Height) * inch], // d
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height) * inch], // e
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height - Board_Space) * inch], // f
[((Top_Width * 2 / 3))* inch,(Height - Board_Space) * inch], // g
[((Top_Width * 2 / 3))* inch,(Height) * inch], // h
[(Top_Width) * inch, (Height) * inch], // 3
[(Top_Width) * inch,(Height - Ledge) * inch], // 4
[(Bottom_Width) *inch, 0]]); // 5
}

module OuterCurvedCrossing(D) {
// Main Outer curved body
echo("Outer: angle ", (Piece_Length / (2 * 3.14159 * (D/2))) * 360);
rotate_extrude(angle=(Piece_Length / (2 * 3.14159 * (D/2))) * 360)
translate([(D/2 + Top_Width) * inch,0,0])
rotate([0,180,0])
polygon([[0,0], // 1
[0,(Height) * inch], // 2
[((Top_Width/3) - Board_Space)* inch,(Height) * inch], // a
[((Top_Width/3) - Board_Space)* inch,(Height - Board_Space) * inch], // b
[((Top_Width/3))* inch,(Height - Board_Space) * inch], // c
[((Top_Width/3))* inch,(Height) * inch], // d
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height) * inch], // e
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height - Board_Space) * inch], // f
[((Top_Width * 2 / 3))* inch,(Height - Board_Space) * inch], // g
[((Top_Width * 2 / 3))* inch,(Height) * inch], // h
[(Top_Width) * inch, (Height) * inch],
[(Top_Width) * inch,(Height - Ledge) * inch],
[(Bottom_Width) *inch, 0]]);
}
module Slots() {
translate([0,Board_Space/2 * inch, ((Board_Space/2) + Height - Board_Space) * inch])
rotate([0, 90, 0])
linear_extrude(height = (Diameter/2 + (Top_Width * 4)) * inch)
square(size = Board_Space * inch, center = true);

}
module Inner2CurvedCrossing(D) {
// Main Inner curved body
echo("Inner2: angle ", (Piece_Length / (2 * 3.14159 * (D/2))) * 360);
rotate_extrude(angle=(Piece_Length / (2 * 3.14159 * (D/2))) * 360)
translate([(D/2 - (Top_Width * 2)) * inch,0,0])
polygon([[0,0], // 1
[0,(Height) * inch], // 2
[((Top_Width/3) - Board_Space)* inch,(Height) * inch], // a
[((Top_Width/3) - Board_Space)* inch,(Height - Board_Space) * inch], // b
[((Top_Width/3))* inch,(Height - Board_Space) * inch], // c
[((Top_Width/3))* inch,(Height) * inch], // d
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height) * inch], // e
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height - Board_Space) * inch], // f
[((Top_Width * 2 / 3))* inch,(Height - Board_Space) * inch], // g
[((Top_Width * 2 / 3))* inch,(Height) * inch], // h
[(Top_Width) * inch, (Height) * inch],
[(Top_Width) * inch,(Height - Ledge) * inch],
[(Bottom_Width) *inch, 0]]);
}

module Outer2CurvedCrossing(D) {
// Main Outer curved body
echo("Outer2: angle ", (Piece_Length / (2 * 3.14159 * (D/2))) * 360);
rotate_extrude(angle=(Piece_Length / (2 * 3.14159 * (D/2))) * 360)
translate([(D/2 + (Top_Width * 2)) * inch,0,0])
rotate([0,180,0])
polygon([[0,0], // 1
[0,(Height) * inch], // 2
[((Top_Width/3) - Board_Space)* inch,(Height) * inch], // a
[((Top_Width/3) - Board_Space)* inch,(Height - Board_Space) * inch], // b
[((Top_Width/3))* inch,(Height - Board_Space) * inch], // c
[((Top_Width/3))* inch,(Height) * inch], // d
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height) * inch], // e
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height - Board_Space) * inch], // f
[((Top_Width * 2 / 3))* inch,(Height - Board_Space) * inch], // g
[((Top_Width * 2 / 3))* inch,(Height) * inch], // h
[(Top_Width) * inch, (Height) * inch],
[(Top_Width) * inch,(Height - Ledge) * inch],
[(Bottom_Width) *inch, 0]]);
}

Here is a listing of the Grade Crossing Straight.scad file:

//
// Customizable Straight Grade Crossing - Lionel O Tubular Track
// Mark DiVecchio
// March 2018
// Original development using OpenSCAD 2017.01.20
//
// This SCAD script is licensed under a
// Creative Commons Attribution-NonCommercial 3.0 Unported License.
//
// V1.0 - Original release
// V2.0 - adds ramps
//
// http://www.silogic.com/trains/layout.html
//
// in slicer, rotate y = 180 deg, rotate z = 45 deg (to get long print lines)
// use 2 bottom layers, 0 top layers, rectilinear bottom layers

$fn=200*1;
//
// CUSTOMIZING
//
/* Configuration */
// Length of the crossing in inches
Piece_Length = 6.0; // [3:0.5:10]
// Width of each crossing segment in inches (Leave enough space for the wheel flanges)
Top_Width = 0.4;
// Number of sections to break the crossing into
Sections_per_Piece = 5; //[1:10]
// Create grade crossing or ramp (will invert the ramps for printing)?
To_Print = "grade"; // [grade,ramp]
// Ramp Height in inches
Ramp_Height = 0.717;
// Ramp Length in inches
Ramp_Length = 3; //[2:10]
// Ramp Thickness in inches
Ramp_Thickness = 0.1; //[0.1,0.15,0.2,0.25]
//
/* [Hidden] */
// Bottom Width
Bottom_Width = Top_Width - 0.25;
// Height of segment - based on measured tubular track
Height = 0.319;
// Ledge
Ledge = 0.100;
// Conversion inches to millimeters
inch=25.4;
// Board Spacing slot
Board_Space = 0.02;

print_part();

/////////////
// Modules //
/////////////

module print_part() {

translate([ -(((2 * Top_Width) + Board_Space) * inch), 0, 0 ]) {
if (To_Print == "grade") difference() {
union () {
StraightCrossingInner(0, 0 * (Top_Width + Board_Space));
StraightCrossingInner(0, 1 * (Top_Width + Board_Space));
StraightCrossingOuter(180, 2 * (Top_Width + Board_Space));
StraightCrossingOuter(180, 3 * (Top_Width + Board_Space));
}
union () {
for (chunks = [1 : Sections_per_Piece]) {
translate ([0, ((Piece_Length * chunks/Sections_per_Piece) - Board_Space) * inch, 0]) Slots();
}
}
}
if (To_Print == "ramp") {
rotate([180, 0, 0]) {
StraightRamp(0,0);
StraightRamp(180, ((2 * (Ramp_Length)) + Board_Space) + 4 * (Top_Width + Board_Space));
}
}
if (To_Print == "grade") {
%StraightRamp(0,0);
%StraightRamp(180, ((2 * (Ramp_Length)) + Board_Space) + 4 * (Top_Width + Board_Space));
}
}
}

module StraightRamp(Angle, Mvmt) {
// Ramp up
translate([(-Ramp_Length - Board_Space) * inch, Piece_Length * inch, -(Ramp_Height - Height) * inch])
rotate([90, 0, 0])
linear_extrude(height = Piece_Length * inch)
translate([(Mvmt) * inch, 0, 0])
rotate([0, Angle, 0])
rotate([0, 0, To_Print =="ramp" ? -atan(Ramp_Height/Ramp_Length): 0])
polygon([[0,0],
[Ramp_Length * inch, Ramp_Height * inch],
[Ramp_Length * inch, (Ramp_Height - Ramp_Thickness) * inch],
[(Ramp_Length - 0.5) * inch, (Ramp_Height - Ramp_Thickness - (0.5) * (Ramp_Height / Ramp_Length)) * inch],
[(Ramp_Length - 0.5) * inch, 0],
[(Ramp_Length - 0.5 - Ramp_Thickness) * inch, 0],
[(Ramp_Length - 0.5 - Ramp_Thickness) * inch, (Ramp_Height - Ramp_Thickness - (0.5 + Ramp_Thickness) * (Ramp_Height / Ramp_Length)) * inch],
[(Ramp_Thickness * Ramp_Length / Ramp_Height) * inch, 0]
]);
}

module StraightCrossingInner(Angle, Mvmt) {
// Main straight body
translate([0, Piece_Length * inch, 0])
rotate([90, 0, 0])
linear_extrude(height = Piece_Length * inch)
translate([(Mvmt) * inch, 0, 0])
rotate([0, Angle, 0])
polygon([[0,0], // 1
[0,(Height) * inch], // 2
[((Top_Width/3) - Board_Space)* inch,(Height) * inch], // a
[((Top_Width/3) - Board_Space)* inch,(Height - Board_Space) * inch], // b
[((Top_Width/3))* inch,(Height - Board_Space) * inch], // c
[((Top_Width/3))* inch,(Height) * inch], // d
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height) * inch], // e
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height - Board_Space) * inch], // f
[((Top_Width * 2 / 3))* inch,(Height - Board_Space) * inch], // g
[((Top_Width * 2 / 3))* inch,(Height) * inch], // h
[(Top_Width) * inch, (Height) * inch], // 3
[(Top_Width) * inch,(Height - Ledge) * inch], // 4
[(Bottom_Width) *inch, 0]]); // 5
}
module StraightCrossingOuter(Angle, Mvmt) {
// Main straight body
translate([0, Piece_Length * inch, 0])
rotate([90, 0, 0])
linear_extrude(height = Piece_Length * inch)
translate([(Mvmt + Top_Width) * inch, 0, 0])
rotate([0, Angle, 0])
polygon([[0,0], // 1
[0,(Height) * inch], // 2
[((Top_Width/3) - Board_Space)* inch,(Height) * inch], // a
[((Top_Width/3) - Board_Space)* inch,(Height - Board_Space) * inch], // b
[((Top_Width/3))* inch,(Height - Board_Space) * inch], // c
[((Top_Width/3))* inch,(Height) * inch], // d
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height) * inch], // e
[((Top_Width * 2 / 3) - Board_Space)* inch,(Height - Board_Space) * inch], // f
[((Top_Width * 2 / 3))* inch,(Height - Board_Space) * inch], // g
[((Top_Width * 2 / 3))* inch,(Height) * inch], // h
[(Top_Width) * inch, (Height) * inch], // 3
[(Top_Width) * inch,(Height - Ledge) * inch], // 4
[(Bottom_Width) *inch, 0]]); // 5
}
module Slots() {
translate([0, 0, (Height - Board_Space) * inch])
cube([(Board_Space + Top_Width) * 4 * inch, Board_Space * inch, Board_Space * inch]);
}


OpenSCAD screen grab



This shows the curved crossing in OpenSCAD. The planks between the track and the ramps are shown. The curvature of the parts change depending on the track radius/diameter that you select.



Here is a photo of a grade crossing with ramps on a O-54 curve. I need to add some Sulptamold or lichen to hide the open space under the ramps. The planks are glued to the track. Notice that there is wheel flange space along the outer rails. The planks are also designed so the top is recessed below the top of the tubular rails.


Station Signs

Some simple station name signs for the Plasticville stations on my layout. Designed to fit into the slots on the roof that normally hold the Plasticville name. This one is named Struthers, a real life station on the P&LE. Printed in black PLA with raised lettering painted white.




Tower Signs

Tower name signs for the Plasticville Switch Towers that I use. The tower names are from real life P&LE towers. These fit into the slots molded into the switch tower's roof. Printed in black PLA with raised lettering painted white.











Stairs

Customizable stairs for your model train layout. I printed these in O Scale (1/4" to the foot) for my toy train layout. Set CreateSTL to "Display" for SCAD to display the stairs as 3-D stairs. Set it to "Print" to create a flat layout than can be exported to an STL file and printed. Then it needs to be glued together.

Some combinations of setting of the physical parameters of the stairs may not be buildable in the real world and some may crash the OpenSCAD program.

Stair values from this web page:

https://www.calculator.net/stair-calculator.html

Use the "Comprehensive Version" of the Stair Calculator.

This program is capable of building every stair possible. I believe that if you always make the Total Rise equal to an integral multiple of the Rise, the program will be able to build the stair.

Enter your values into the equations on that web page. Select the "Use One Run" tab. Set "Fixed Rise", "Has tread", "No headroom restriction" and "Standard stringer mount" Also enter values here for Run, Total Rise, Rise and Tread thickness. Enter a Thread thickness of 1 inch. Then press "Calculate".

Enter the Results from that web page into this script's customizer. You may have to renter the Rise if the calculator could not work with your suggested Rise. The Stairs OpenSCAD program does not need every Result value.

More information about stairs equations:

https://www.jlconline.com/training-the-trades/stair-stringers-calculation-and-layout_o

Uses Build Plate from the Thingiverse library.

3D printers may have a hard time with HO and N part thickness. G scale stairs may not fit on a typical build plate and each part of the stairs may have to be printed individually.

You can get the latest OpenSCAD code from the Thingiverse web page:   https://www.thingiverse.com/thing:3971212


K-Rail (Barrier Rail)

A K-Rail print done for my O Gauge (1/4 inch to the foot) toy train layout. Roughly based on a "Jensen Precast 10' Barrier Rail with Fence Post Holes" except that I made it 12' 7" long.

You can find the Jensen spec for this K-Rail with an internet search.


You can get the latest OpenSCAD code from the Thingiverse web page: https://www.thingiverse.com/thing:4097927


This site prepared and maintained by Mark DiVecchio

email :  markd@silogic.com

SD&A HOME
 
 Mark's Home Page

The DiVecchio genealogy home page
The Frazzini genealogy home page

This site will be under construction for a while.