--- title: Modifying models ---

We know that models are relatively simple objects with a well known recursive structure. This allows us to modify them for different purposes. Let's modify and combine two different models in one drawing.

For this example we will use ovals to make an oval L shape. We begin by creating a model function that has two ovals:

{% highlight javascript %} //render two ovals which overlap var makerjs = require('makerjs'); function ovalL(width, height, thickness) { var ovalH = new makerjs.models.Oval(width, thickness); var ovalV = new makerjs.models.Oval(thickness, height); this.models = { h: ovalH, v: ovalV }; } var svg = makerjs.exporter.toSVG(new ovalL(100, 100, 37)); document.write(svg); {% endhighlight %}

There are overlapping arcs in the lower left corner. We can remove them if we know their id and position in the heirarchy. There are several ways we can inspect this model, here are a few:

By looking at the source code we know that an Oval is a RoundRectangle and that the ids for arcs are BottomLeft, BottomRight, TopLeft and TopRight. The ids for the sides are Left, Right, Top and Bottom. Also, we need to note the orientation of these lines so we know which are origin and end points.

To remove a path we use the JavaScript delete keyword:

{% highlight javascript %} //render two ovals which overlap var makerjs = require('makerjs'); function ovalL(width, height, thickness) { var ovalH = new makerjs.models.Oval(width, thickness); var ovalV = new makerjs.models.Oval(thickness, height); //delete the lower arcs from the vertical oval delete ovalV.paths.BottomLeft; delete ovalV.paths.BottomRight; //delete the inside arc of the horizontal delete ovalH.paths.TopLeft; this.models = { h: ovalH, v: ovalV }; } var svg = makerjs.exporter.toSVG(new ovalL(100, 100, 37)); document.write(svg); {% endhighlight %}

The next step is to eliminate the overlap in the lines. Here are two approaches to do this:

Adjust only the x or y component of the point:

{% highlight javascript %} //render an L shape, modifying points by their x and y var makerjs = require('makerjs'); function ovalL(width, height, thickness) { var ovalH = new makerjs.models.Oval(width, thickness); var ovalV = new makerjs.models.Oval(thickness, height); delete ovalV.paths.BottomLeft; delete ovalV.paths.BottomRight; delete ovalH.paths.TopLeft; //move the x of the horizontal's top ovalH.paths.Top.end[0] = thickness; //move the y of the vertical's right ovalV.paths.Right.origin[1] = thickness; this.models = { h: ovalH, v: ovalV }; } var svg = makerjs.exporter.toSVG(new ovalL(100, 100, 37)); document.write(svg); {% endhighlight %}

Share a point on both lines:

{% highlight javascript %} //render an L shape, sharing a point var makerjs = require('makerjs'); function ovalL(width, height, thickness) { var ovalH = new makerjs.models.Oval(width, thickness); var ovalV = new makerjs.models.Oval(thickness, height); delete ovalV.paths.BottomLeft; delete ovalV.paths.BottomRight; delete ovalH.paths.TopLeft; //set to the same point ovalH.paths.Top.end = ovalV.paths.Right.origin = [thickness, thickness]; this.models = { h: ovalH, v: ovalV }; } var svg = makerjs.exporter.toSVG(new ovalL(100, 100, 37)); document.write(svg); {% endhighlight %}

Let's progress this example further, by modifying an L shape into a C shape. Create a new model function for C, and immediately create an L within it. The C may create a new models object for itself, and nest the L inside; alternatively, C can just assume L's models object:

{% highlight javascript %} //render an L with an oval over it var makerjs = require('makerjs'); function ovalL(width, height, thickness) { var ovalH = new makerjs.models.Oval(width, thickness); var ovalV = new makerjs.models.Oval(thickness, height); delete ovalV.paths.BottomLeft; delete ovalV.paths.BottomRight; delete ovalH.paths.TopLeft; ovalH.paths.Top.end = ovalV.paths.Right.origin = [thickness, thickness]; this.models = { h: ovalH, v: ovalV }; } function ovalC(width, height, thickness) { //assume the same models as L this.models = new ovalL(width, height, thickness).models; //add another oval this.models.h2 = new makerjs.models.Oval(width, thickness); //move it to the top this.models.h2.origin = [0, height - thickness]; } //using C instead of L var svg = makerjs.exporter.toSVG(new ovalC(100, 100, 37)); document.write(svg); {% endhighlight %}

Just as before, we need to delete the overlapping paths using the delete keyword. Let us also make a short alias for this.models to save us some keystrokes:

{% highlight javascript %} //render an L and form a C var makerjs = require('makerjs'); function ovalL(width, height, thickness) { var ovalH = new makerjs.models.Oval(width, thickness); var ovalV = new makerjs.models.Oval(thickness, height); delete ovalV.paths.BottomLeft; delete ovalV.paths.BottomRight; delete ovalH.paths.TopLeft; ovalH.paths.Top.end = ovalV.paths.Right.origin = [thickness, thickness]; this.models = { h: ovalH, v: ovalV }; } function ovalC(width, height, thickness) { //set local var m for easy typing var m = this.models = new ovalL(width, height, thickness).models; m.h2 = new makerjs.models.Oval(width, thickness); m.h2.origin = [0, height - thickness]; //delete overlapping arcs again delete m.h2.paths.TopLeft; delete m.h2.paths.BottomLeft; delete m.v.paths.TopRight; } var svg = makerjs.exporter.toSVG(new ovalC(100, 100, 37)); document.write(svg); {% endhighlight %}

Lastly, we need our overlapping lines to meet at a common point. Notice that the new oval h2 has a different origin the the previous ovals. So, we must originate for all of the ovals to share the same coordinate space. Afterwards, we can assign the common point to both lines.

In the Play editor, try removing the call to originate to see the results without it.

{% highlight javascript %} //render a C shape var makerjs = require('makerjs'); function ovalL(width, height, thickness) { var ovalH = new makerjs.models.Oval(width, thickness); var ovalV = new makerjs.models.Oval(thickness, height); delete ovalV.paths.BottomLeft; delete ovalV.paths.BottomRight; delete ovalH.paths.TopLeft; ovalH.paths.Top.end = ovalV.paths.Right.origin = [thickness, thickness]; this.models = { h: ovalH, v: ovalV }; } function ovalC(width, height, thickness) { var m = this.models = new ovalL(width, height, thickness).models; m.h2 = new makerjs.models.Oval(width, thickness); m.h2.origin = [0, height - thickness]; delete m.h2.paths.TopLeft; delete m.h2.paths.BottomLeft; delete m.v.paths.TopRight; //h2 has paths relative to h2 origin, //we need to originate to share the point makerjs.model.originate(this); //share the point m.h2.paths.Bottom.origin = m.v.paths.Right.end = [thickness, height - thickness]; } var svg = makerjs.exporter.toSVG(new ovalC(100, 100, 37)); document.write(svg); {% endhighlight %}