Introduction
I am an adult fan of LEGO and while working on my recent LEGO project, I had to build a dome made of LEGO bricks. After trying a couple of LEGO CAD applications, I still was having difficulty building the dome. Then I stumbled upon a LEGO dome creator application from a guy called Arthur Gugick. This application was developed using VB6 and it had some bugs like the form would be cleared once it was minimised. This application gives the height of the dome and every stud location and this is also how WPF 3D Dome Creator functions. However it was all 2D, one could not visualise how the dome will look like. So I contacted Arthur and asked him if it would be possible to send the source code. He was more than happy to provide it and I took that as a base for the WPF 3D Dome Creator.
About LDrawPartLib
LDrawPartLib
was developed by me for LEGO CAD application similar to MLCad, which is still work in progress but the library is complete. LDrawPartLib
uses the LDraw part library for the part geometry. LDraw
is an open source standard of LEGO CAD application. They have a very active community and regularly update the library with new parts. I feel that discussing about LDrawPartLib
here is beyond the scope of this article. However, if you are interested in how the LDrawPartLib
parses and creates 3D LEGO part, you will have to go through the code, which had decent amount of comments and the documentation from LDraw
. You can of course contact me anytime if you have something very specific.
About the Dome Creator
I have used this application as a way to learn more about WPF, 3D and the famed MVVM. This application is understanding for MVVM and WPF implementation should be done. I am open to your comments and ways to improve this application. Since this application uses only one part, all the required files are places in the “Parts” folder. If you want to use the LDraw
parts library, you will need to download it from here and the place the path in the App.Config. Also ldconfig.ldr
, which a part of LDraw
, needs to placed in the application path as it has all the details about the part colors.
The application itself is very simple to use. Choose the type of dome that you would like to build, set the various parameters like the diameter and the height of the dome, the height is consider only when the dome type is not spherical. You can change the color of the dome by clicking on the color palette.
Points of Interest
First and foremost, it uses WPF 3D. I have used WPF 3D as I wanted to know what are its capabilities. It is a great 3D framework, however I seriously doubt that this will be used for developing games. There are many drawbacks, for one the framework does not come with built in support for creating basic figures like cubes, spheres, etc., secondly, as I learnt the hard way that drawing line on a 3D canvas can be a real pain. However, I later found out about how to draw lines by using 3DTools and a library from Charles Petzold. He has also written an excellent book on WPF 3D named 3D Programming for Windows. The former has a bug in the implementation, more on this here, and so I did not to use the line implementation of 3DTools. However, the TrackBall implementation of 3DTools
is fantastic. The second one has some excellent features but the performance goes down considerably as the number parts with lines increases in my 3D scene. If you want to see the parts with lines, uncomment the following line:
public class Dome3DViewModel : DomeViewModel
{
...
public void CalculateDomeValues() {
...
int y = (currentHeight - noOfPlates) * (int)ScaleHeight;
for (int i = 0; i < noOfPlates; i++, y += (int)ScaleHeight) {
Point3D pt = new Point3D(x * ScaleWidth, y, z * ScaleWidth);
PartColors color =
(PartColors)Enum.Parse(typeof(PartColors),
MainWindowVM.ColorChooserVM.CurrentColor.Name);
Part3D part =
new Part3D( PLATE_PART_CODE,
PLATE_PART_CODE, color) { Position = pt };
Viewport.Children.Add(part);
}
...
}
}
There is an excellent tutorial on WPF 3D here.
Secondly, as I mentioned before, the program by Arthur gives the height in LEGO plates at a particular location. I could have inserted the exact number of plates from the “ground” but this however would create a solid dome. Hence, I decided to add only “viewable” plates. This is achieved by finding which of its eight neighbours in the grid have the lowest height and then add only the difference between the lowest and the current height. In order to achieve this, I used the following:
List<int> neighbours = new List<int>();
...
FillNeighbours(diameter, z, drCurrent, neighbours);
if (drPrev != null) FillNeighbours(dt.Rows.Count, z, drPrev, neighbours);
if (drNext != null) FillNeighbours(dt.Rows.Count, z, drNext, neighbours);
neighbours.Sort();
if (drNext == null || drPrev == null || z == 0 || z == (diameter - 1))
noOfPlates = currentHeight;
else if (currentHeight == neighbours[0] && currentHeight > 0)
noOfPlates = 1;
else
noOfPlates = currentHeight - neighbours[0];
Thirdly, I wanted to have access the one view model from other. To achieve this, I created a base class called ApplicationViewModel
.
public abstract class ApplicationViewModel : ViewModelBase
{
#region ctor
protected ApplicationViewModel(MainWindowViewModel mainWindowModel) {
MainWindowVM = mainWindowModel;
}
#endregion
#region Public Properties
public MainWindowViewModel MainWindowVM { get; set; }
#endregion
}
The constructor of this class takes MainWindowViewModel
as a parameter. All the view models that need to talk to each other in the application derive from ApplicationViewModel
.
public class ParametersViewModel : ApplicationViewModel
{
#region ctor
public ParametersViewModel(MainWindowViewModel mainWindowModel)
: base(mainWindowModel) {
DomeDiameter = 12;
DomeHeight = 16;
}
#endregion
...
}
The MainWindowViewModel
has properties for each of these models.
public class MainWindowViewModel : ViewModelBase
{
#region ctor
public MainWindowViewModel() {
ParametersVM = new ParametersViewModel(this);
Dome2DVM = new Dome2DViewModel(this);
Dome3DVM = new Dome3DViewModel(this);
ColorChooserVM = new ColorChooserViewModel(this);
}
#endregion
#region Public Properties
public ParametersViewModel ParametersVM { get; set; }
public Dome2DViewModel Dome2DVM { get; set; }
public Dome3DViewModel Dome3DVM { get; set; }
public ColorChooserViewModel ColorChooserVM { get; set; }
#endregion
}
Conclusion
As a learner, I would love to know what you think about the way in which this application is developed. It would be great if the criticism is constructive.
Lastly, LEGO is a registered trademark of the LEGO Group, which does not sponsor, endorse, or authorize this article or this application. Visit the official Lego website at www.lego.com.
History
- 14th January, 2011: Initial post