Skip to content

3. Sketch

raydeleu edited this page Nov 16, 2023 · 4 revisions

3.1 Create a new sketch or drawing

To start a sketch, use the new Sketcher command. Note the keyword new that is required to create a new object of the type Sketcher.

let sketch = new Sketcher("XZ",-5)
".sketchCommands"        (see below)
.close()                    // ends the sketch with line to starting point
.done()                     // ends the sketch without closing
.closeWithMirror()          // closes the sketch with mirror on axis from start to end

The definition of a sketch refers to a plane in 3D space where the sketch is drawn. Most often this will be either the "XY" plane (top view), the "XZ" plane (front view) or the "XY" plane (side view). It is also possible to define an offset to these planes, as was done in the code sample above.

An alternative and often preferred method to create a sketch is to use the function draw() to create a drawing. A drawing can be understood as an adapted version of a sketch. A sketch starts with identifying the sketching plane first and then defining a wire. As the plane is defined up front, the sketch is in fact a 3D shape from its origin. In contrast a drawing is considered a pure 2D shape that can be placed on a plane after its creation. Compared to a sketch a drawing has the following advantages:

  • drawings can be translated, rotated (in 2D space) and scaled;
  • drawings can be used in 2D boolean operations;
  • drawings can be exported directly in 2D formats;
  • drawings can be placed on other shapes, not only planes

The drawing can be defined with the draw() function. As this function already includes the creation of a new object the new keyword is not needed. The starting point of the drawing can be defined by adding a 2D point as a parameter to the draw(), for example draw([5,5]).

const shape1 = draw()
    .lineTo([20,0])
    .line(0,5)
    .hLine(10)
    .vLine(5)
    .polarLineTo([22,45])
    .polarLine(10,150)
    .halfEllipse(-10, -15, 5)
    .smoothSpline(2, -5)
    .close() 

After its creating, a drawing has to be placed on a plane, using the method .sketchOnPlane. Through this method, a drawing can also be translated and rotated in 3D space. You can achieve this by translating and pivoting the plane on which the drawing is placed. For example, using the following code:

  const bottomPlane = makePlane().pivot(20, "Y").translateZ(80);
  const bottomCircle = drawCircle(9).sketchOnPlane(bottomPlane);

first a Plane is defined, which is first pivoted by 20 degrees along the Y-axis and then translated up 80 mm on the Z-axis. Note that you can not translate or rotate the sketch after it is placed on a plane. The full set of commands to create and position planes is :

method description
.sketchOnPlane(plane,offset) place the drawing on a given plane
makePlane() create a basic plane, default is on the XY plane
.pivot(degrees, axis) rotate the plane x degrees around the given axis
.translate translate the plane
.translateZ translate the plane along the Z-axis
.translateY translate the plane along the Y-axis
.translateX translate the plane along the X-axis

A standard plane is identified "XY", "XZ", "YZ", but using the function makePlane() you can also define a new plane with its own name.

There are a number of ".methods" to define a sketch that can be used either on a new Sketcher() object or on a draw() object. These will be explained in the following paragraphs.

3.2 Create straight lines

Straight lines can be sketched using the line functions. Be aware that points are generally defined as a tuple or array, i.e. enclosed in square brackets. This array either contains the absolute distance in the x and y direction from the origin, or the distance and angle in case of polar coordinates. Relative distances to the x- and y-axis are defined as two separate values dx and dy.

method description
.movePointerTo([x,y]) move pointer without drawing, can only be used at start
.lineTo([x,y]) line to absolute coordinates
.line(dx,dy) line to relative coordinates
.vLineTo(y) vertical line to absolute y
.vLine(dy) vertical line to relative y
.hLineTo(x) horizontal line to absolute x
.hLine(dx) horizontal line to relative x
.polarLineTo([radius,theta]) line to absolute polar coordinates. Note that the absolute polar coordinates are defined as an vector [radius,theta]
.polarLine(distance,angle) line to relative polar coordinates
.tangentLine(distance) tangent extension over distance

3.3 Create arcs and ellipses

The following commands are available to create circular and elliptical arcs in your sketch. Just as with lines be aware that points are generally defined as a tuple or array, i.e. enclosed in square brackets. Relative distances to the x- and y-axis are defined as two separate values dx and dy. The elliptic curves can be defined in more detail with three extra parameters. If the values are omitted the default values are used.

method description
.threePointsArcTo(point_end,point_mid) arc from current to end via mid, absolute coordinates
.threePointsArc(dx,dy,dx_via,dy_via) arc from current to end via mid, relative coordinate
.sagittaArcTo(point_end,sagitta) arc from current to end with sag , absolute coordinates
.sagittaArc(dx,dy,sagitta) arc from current to end with sag, relative coordinates
.vSagittaArc(dy,sagitta) vertical line to endpoint with sag, relative y
.hSagittaArc(dx,sagitta) horizontal line to endpoint with sag, relative x
.tangentArcTo([x,y]) arc tangent to current line to end, absolute coordinates
.tangentArc(dx,dy) arc tangent to current line to end, relative coordinates
.ellipseTo([x,y],r_hor,r_vert) ellipse from current to end, absolute coordinates, radii to hor and vert
.ellipse(dx,dy,r_hor,r_vert) ellipse from current to end, relative coordinates, radii to hor and vert
.ellipse(dx,dy,r_h,r_v,deg rotation, long_way?, counter? extra parameters ellipse, rotation around axis defined as [x,y,z] array
.halfEllipseTo([x,y],r_min, long_way?) half ellipse with r_min as sag, absolute coordinates
.halfEllipse(dx,dy,r_min, long_way?) half ellipse with r_min as sag, relative coordinates

These functions create only partial arcs as the starting point and the end point cannot be identical. To create a circle you therefore need to define two arcs. The following code shows how to draft a circle. Note that the same can be achieved with the function sketchCircle or drawCircle (see next sections).

const {draw, Sketcher} = replicad

function main()
{
    let circle = new Sketcher("XY")
    .halfEllipseTo([0,20],10)
    // first half of circle, only one radius needed, 
    // long axis is defined by coordinates
    .ellipseTo([0,0],10,10)
    // second half, if r_min and r_max are equal this defines a circle
    .close()
    .extrude(5)

    return circle}

.threePointsArc

The method threePointsArc creates a circular arc through three points. It always tries to create the shortest arc possible from the current point to the end point through the second point. The arc is circular, i.e. has a constant radius, but the centerpoint of the arc is determined by the location of the three points. In most drawings, finding the third point of a curve that results in an arc that is tangent to other elements is not easy. In those cases one of the other methods might be more practical.

.sagittaArc

The sagitta (Latin for arrow) arc is an arc defined by drawing an arc from the starting point to the end point. The "sag" of sagitta defines the distance between the arc and the straight line between the starting and end point (the socalled "chord"). Think of it as taking a flexible band between the start and end point and then flexing this band to either the right or the left side over a distance equal to the "sag". The little icon on the top of this section illustrates the "sag" of this curve. When moving in a clockwise direction, the bulge or sag of the arc is to the left of the straight line between the two outer points of the arc when the value is positive. If you want the bulge to be on the other side, you have to define a negative value for this parameter.

.ellipse

There are several methods to create a part of an ellipse between two points. Most of the arguments to this method are straightforward, such as the definition of the endpoint (either as a point [x,y] or as a distance dx,dy) and the definition of the horizontal and vertical radius of the ellipse. Setting these two equal results in a circular arc. The rotation parameter defines the angle in degrees over which the long axis of the ellipse is rotated. The x-direction has angle 0, the y direction is +90 degrees. The following two parameters are booleans, so can be either true or false. The first of these parameters, in the API reference identified as "sweep" can be understood as taking the short way or the long way. When you fit a complete ellipse between two points, you can choose which way you traverse along the ellipse. In most cases the short way is the preferred solution, thus setting this parameter to false is the default. The last parameter defines whether the curve is drawn clockwise (false, default value) or counter-clockwise (true).

The image below shows 4 options to draw an ellipse from the starting point (indicated with the green circle) to the end point (indicated with the red circle).

Remark 1: in the definition of SVG (scalable vector graphics) the two parameters as discussed above are also available. Here the 'sweep' parameter defines whether the starting angle of the curve is positive or negative (similar to being clockwise or counter-clockwise) and the 'long-arc' parameter defines whether the long or short path should be followed. Often setting the values by trial and error is the quickest solution.

.tangentArc

A tangent arc is tangent to the segment that directly precedes the arc. It will not be tangent to the line following the arc. The image below shows some examples of tangent arc. Note that in one of the cases the curve is drawn clockwise. Using the right-hand rule, the face is pointing away from the viewer. You can think of it like when you turn a screw to the right, it moves away from you.

If you want to create a fillet or rounding that is tangent to two segments, use the method .customCorner(radius) that is explained in the next section.

3.4 Fillets and chamfers in 2D

Creating a rounded edge or fillet in sharp corners of your sketch can be achieved by calculating the parameters for the arc methods described in the previous paragraphs but can also be achieved with a specialized method called customCorner(radius). This method uses the radius of the rounding as an argument and is applied to the corner defined by the last coordinate of the previous drawing command. The method should therefore be placed between the two methods used to define the corner. The following code snippet shows an example how to create a rounded shape. Note that in this case, using a rounding radius that is exactly half the height of the shape fails. If you want to achieve a semi-circle at each end you have to use the arc methods described in the previous section.

As the method has to be placed in between two methods that describe a sharp corner, the method can not be used as the last statement before closing or ending the sketch. In the example below this is solved to shift the startpoint for the definition of the rectangle from the first corner in the bottom left to somewhere along the first line (drawing counterclockwise). Another point worth noting is that when rounding sharp edges, as is done in the example below, the result might be different from what you expect.

Adding 2D fillets to a sketch
const { draw } = replicad;

const main = () => {
  // just lines
  const s1 = 
  draw([20,0])
    .hLine(30)
    .customCorner(5.45)
    .vLine(11)
    .customCorner(5.45)
    .hLine(-50)
    .customCorner(3)
    .line(5,-11)
    .customCorner(5)
    .close();

return [ { shape: s1, color: "blue", name: "Straight lines" }]} 

The method .customCorner(radius) also supports creating chamfers. To achieve this you have to add a second argument to the method: customCorner(radius, "chamfer"). The default value of this argument is "fillet", so it does not have to be added explicitly. The dimension of the chamfer describes the length of the straight line perpendicular to the lines that define the corner. In case of sharp corner it is difficult to predict where this corner will land and what will be the overall dimension of the resulting shape.

Adding 2D chamfers to a sketch
const { draw } = replicad;

const main = () => {
  // just lines
  const s1 = 
  draw([20,0])
    .hLine(30)
    .customCorner(5, "chamfer")
    .vLine(11)
    .customCorner(5.45)
    .hLine(-50)
    .customCorner(3,"chamfer")
    .line(5,-11)
    .customCorner(5, "chamfer")
    .close();

return [
    { shape: s1, color: "blue", name: "Straight lines" }
]
} 

3.5 Free form curves

Free form curves can be created with the methods listed below.

method description
.bezierCurveTo([x,y],points[]) Bezier curve to end along points[]
.quadraticBezierCurveTo([x,y],[x_ctrl,y_ctrl]) Quadratic bezier curve to end with control point
.cubicBezierCurveTo([x,y],p_ctrl_start,p_ctrl_end) Cubic bezier curve with begin and end control points
.smoothSplineTo([x,y],splineconfig) smooth spline to end, absolute coordinates
.smoothSpline(dx,dy,splineconfig) smooth spline to end, absolute coordinates
{startTangent:angle,endTangent:angle / "symmetric"} splineconfig = configuration of spline points
drawPointsInterpolation(array[[pt1],[pt2]..[ptn]]) create a drawing of a curve that is an interpolation of all points in the array

A Bezier curve is a type of curve that is defined by a set of control points. It was developed by French engineer Pierre Bezier for use in the design of Renault cars in the 1960s. The important feature of a Bezier curve is that the control points influence the shape of the curve, but the curve does not necessarily pass through these points. In case of a quadratic Bezier curve there is only one control point between the startpoint and endpoint of the curve which defines the direction of the curve at both ends. Using a cubic Bezier curve it is possible to adjust the slope of the curve at both ends. The control points may be considered as a kind of magnet, pulling the curve towards it. The further the control points are placed, the stronger the curve will deviate from a straight line between the begin and endpoints. The .bezierCurveTo method allows a large array of control points to define the shape of the curve, but adjusting these endpoints is difficult without being able to judge the effect of these points.

Illustration of different Bezier curves

The .smoothSpline method defines a curve that passes through each point. The shape of the curve can be adjusted using the spline configuration. An example of the application of this function is shown in <>. The startTangent and endTangent define the angle of the curve at its starting and end point. The factor defines how far the curve is drawn into the direction of the tangent. The larger the factor, the longer the curve wants to proceed in the direction of the specified tangent.

Example of the application of the smoothSpline method

It is not always necessary to use the configuration at the begin and end point of a smoothSpline. In the example in <> the .smoothSpline method is used between two arcs. The smoothSpline adapts to the tangent of the previous line segment. Without any previous line segment it uses a tangent of 0 degrees, i.e. in the x-direction (assuming a drawing area aligned with x,y coordinates). The smoothSpline does not adjust the endTangent to the next segment, so without any specification the endTangent is 0 degrees, along the x-axis. In <> this yields the intended result without any additional configuration.

Using the smoothSpline between two arcs without config

The code below illustrates how a smoothSpline curve is either tangent to the x-axis or follows the tangent of the previous line segment. It also demonstrates that with a factor of 2.63 the resulting curve is very close to a perfect arc.

Comparison of smoothSpline curves

The function drawPointsInterpolation(array of points) is a drawing function that draws a curve through all points listed in the array of 2D points. The code sample below shows an example how this function can be used to create the shape of an airfoil by creating an array that lists 2D points along the contour of the airfoil. Note that the curve starts and ends at the sharp trailing edge of the airfoil. The last point of the array has to be identical to the first point to create a closed curve for extrapolation. Closing the curve in another way is difficult as this drawing is created with a function, not a method that can be followed by any of the other drawing methods listed above.

let chord = 100 
let span  = 100
let airfoilPointsLarge = airfoilPoints.map(function([x,y]){return [x*chord,y*chord]}) 
let airfoil = drawPointsInterpolation(airfoilPointsLarge).sketchOnPlane("XZ");
let wing = airfoil.extrude(span)

3.6 Pre-baked sketches and drawings

The methods described in the previous chapter contain the building blocks that can be used to create any sketch or drawing. To simplify the creation of standard shapes like rectangles, circles and ellipses, some standard functions are available in Replicad. The function encapsulates the process to create a sketch or drawing, so only using the function with the required parameters is sufficient to create a sketch. Note that the draw() functions still have to be placed on a plane before they can be used to create 3D shapes. The sketch is always produced on the "XY" plane, centered at [0,0,0] unless this is changed using the optional configuration defined for the function (see table)

method description
sketchRectangle(length,width) create a sketch of a rectangle with length and width
sketchRoundedRectangle(length,width,fillet, {config?}) create a sketch of a rounded rectangle
sketchCircle(radius,{config?}) create a sketch of a circle
sketchEllipse(xRadius,yRadius,{config?}) create a sketch of an ellipse
sketchPolysides(radius,numSides,sagitta?,{config?}) create a sketch of a regular polygon, where the sides of the polygon are lines or arcs with a sag from the straight line. The radius is defined without the sagitta.
sketchText(string,{textConfig?},{planeConfig} create a sketch of a text. The textConfig defines the fontFamily, fontSize, startX,startY
{config?} = configuration of pre-baked sketch {plane:"XZ",origin:dist/[point]})
sketchFaceOffset(shape,thickness) create a sketch by defining an offset from an existing face in the scene
sketchParametricFunction(function,{planeconfig},namedParameters?,approximation? create a sketch of a parametric function

Similarly as for the sketches, some pre-baked drawings are available to speed-up the creation of standard shapes. As the draw() object also allows boolean operations the creation of more complex shapes can be achieved by combining a number of standard shapes.

method description
drawRoundedRectangle(length, width, radius) Draw a rounded rectangle centered at [0,0]
drawSingleCircle(radius) Creates the Drawing of a circle as one single curve. The circle is centered on [0, 0]
drawCircle(radius) Draw a circle with a given radius, centered at [0,0]
drawSingleEllipse(majRadius,minRadius) Creates the Drawing of an ellipse as one single curve. The ellipse is centered on [0, 0], with axes aligned with the coordinates.
drawPolysides(radius, sidesCount,sagitta = 0) Creates the Drawing of an polygon in a defined plane. The sides of the polygon can be arcs of circle with a defined sagitta. The radius defines the out radius of the polygon without sagitta.
drawText("text",{ startX: 0, startY: 0, fontSize: 16, fontFamily: "default" } Draw a 2D text. The options can be used to adjust location, fontsize and font.
drawParametricFunction(function, {options}) Draw a parametric function with variable t. With the option it is possible to adjust the number of intermediate points that are used { pointsCount : 400, start : 0, stop : 1 } and the type of approximation of the curve.
drawPointsInterpolation(points2D[],{approximationConfig:}) Draw a bSpline through the array of points

3.7 Methods for drawings

In the introduction to the chapter on sketches and drawings it was explained that drawings support some additional methods compared to sketches. These methods are listed in the following table.

method description
.clone() create a copy of the shape
.offset(r) create a 2D offset with radius r, shape is rounded with radius, negative inwards
.mirror([center/dir],[origin],mode? ) mode? "center" or "plane"
.translate(xDist,yDist) translate the shape
.rotate(angle,[center]) rotate the shape
.stretch(ratio,direction,origin) scale the shape in a single direction
.cut(cuttingDrawing) create a 2D boolean where the drawing listed as an argument to this method is subtracted from the drawing that this method is acting on.
.intersect(drawing) create a 2D intersection between two drawings
.fuse(other) create a 2D boolean where the drawing listed as an argument is fused to the drawing that this method is acting on
.sketchOnFace(face,scaleMode) The scale mode is "original" for global coordinates, "bounds" for following UV of the receiving face or "native" for the default UV parameters of opencascade
.sketchOnPlane place the drawing on a plane
.toSVG(margin) format the drawing as an SVG image
.toSVGPaths() format the drawing as a list of SVG paths
.toSVGViewBox return the SVG viewbox that corresponds to this drawing

The boolean operations cut, fuse and intersect provide options to shortcut the creation of complicated drawings without the need for complex geometric calculations. Using boolean functions and the pre-baked drawings of a circle and rectangle, creating a shape like an axle with a keyway is very simple. Notice in de code below that a drawing needs to be placed on a plane before any other method can be applied to it.

const { draw, drawCircle, drawRectangle} = replicad;

const main = () => {
let axleRadius = 11
let keySlotHeight = 6
let keySlotWidth  = 2.50  

let axleHole = drawCircle(axleRadius)
let axleHole2 = drawCircle(axleRadius).translate(3*axleRadius,0)
let keySlot  = drawRectangle(2*keySlotWidth,keySlotHeight)
.translate(-axleRadius,0)
let keySlot2  = drawRectangle(2*keySlotWidth,keySlotHeight)
.translate(-axleRadius,0).translate(3*axleRadius,0)
let axleShape = axleHole.cut(keySlot).sketchOnPlane("XZ")
let axleShape2 = axleHole2.fuse(keySlot2).sketchOnPlane("XZ",20)
let axle = axleShape.extrude(25)
let axle2 = axleShape2.extrude(25)

  return [axle,axle2];
};
Creating an axle with a keyway using 2D boolean functions on drawings

The .intersect() method can be used to create shapes based on the intersection of two other shapes. An example is creating a curved slot (see image below). By intersecting a ring with a sector, only a segment of the ring remains. The rounded ends of the curved slot are then added by fusing circles at each end.

Creating a curved slot using an intersection and union of drawings

The following code snippet shows the use of the 2D offset function. Offset only works on a closed curve. The curve is offset with radius r, positive values create an offset outward of the curve, negative values inward. When offsetting outward, the curve is automatically rounded with the radius r. In the code example a rounded rectangle is created by drawing a very thin rectangle, then applying an offset of 5 mm, resulting in a shape with a height of 10 mm and corners rounded with a radius of 5 mm. Then an additional shape is created with an offset of 2 mm. Finally the original shape is subtracted from the offset shape to create a thin walled shape.

const {draw} = replicad

function main()
{
// frontview of receiver is just a rectangle with height 0.1 mm
let frontView = draw()
.movePointerTo([-20,7])
.hLine(40)
.vLine(0.1)
.hLine(-40)
.close()

let contourBody = frontView.offset(5) // shape is offset with r=5
let contourHolder = contourBody.offset(2) // holder is offset with r=2
// not that drawings have to placed on plane before extruding
let gpsFront = contourBody.sketchOnPlane("YZ")
let holderFront = contourHolder.sketchOnPlane("YZ")
let gpsReceiver = gpsFront.extrude(70)
let gpsHolder = holderFront.extrude(72).cut(gpsReceiver)

return [gpsReceiver,gpsHolder]
}

Creating a thin walled shape with an offset

Have a look at https://studycadcam.blogspot.com/ for training exercise for your 2D drawing skills.