# 4. Cnc25D API Outline Creation¶

## 4.1. Cnc25D outline¶

Cnc25D helps you to work on outline before extruding it into 3D parts. Cnc25D outlines are defined in the XY-plan and consist of a series of lines and/or arcs. A line is defined by a start point and an end point. An arc is defined by a start point, a passing-through point and an end point.

Manipulating Cnc25D outline consists of working on 2D points. This requires much less CPU resources as invoking a complete 3D software. If you want to create other types of curve than lines or arcs, you must approximate those curves with multiple small lines.

Cnc25D outline vocabulary:

• outline: a series of segments
• segment: a line or an arc
• start-point: the starting point of a line or an arc
• end-point: the ending point of a line or an arc
• middle-point: the passing-through point of an arc (it doesn’t have to be in the middle of the arc)
• first-point: the start point of the first segment of an outline
• corner: the junction between two consecutive segments.
• corner-point: the end-point of the previous segment or the start-point of the next segment
• rbrr : the router_bit radius request (how to transform a corner to do it millable by a router_bit of radius R?)
• closed outline: True if the end-point of the last segment is equal to the first-point
• outline orientation: Counter Clock Wise (CCW) or Clock Wise (CW) (this has a meaning only for closed outline)
• curved outline: outline representing a curve. The outline approximates the curve with some discrete points.
• tangent inclination: angle between the (Ox) direction and the oriented tangent of a point of an oriented curve.
• outline format A: pythonic description of an outline used as argument by the function cnc25d_api.cnc_cut_outline()
• outline format B: pythonic description of an outline returned by cnc25d_api.cnc_cut_outline() and used as argument by cnc25d_api.outline_arc_line()
• outline format C: pythonic description of a curved-outline used as argument by the function cnc25d_api.smooth_outline_c_curve()
• figure: list of format-B outlines

## 4.2. Cnc25D outline format A¶

In short, the Cnc25D outline format A is a list of list of 3 or 5 floats.

The purpose of the Cnc25D outline format A is to define your wished outline. In addition to the start, middle and end points of the segments, you define for each corner the associated rbrr. That means that you can request different router_bit radius for each corner. In general, you will set the same value for all corners of your outline. But you also have the flexibility to set different rbrr for each corner.

The first element of the outline format A list is the first-point. It is defines by a list of 3 floats: X-coordinate, Y-coordinate and the rbrr of the first-point.

The second element of the outline format A list is the first segment of the outline. If the first segment is a line, it is defines by a list of 3 floats: end-point-X, end-point-Y and the rbrr of the end-point of the segment. If the first segment is an arc, it is defines by a list of 5 floats: middle-point-X, middle-point-Y, end-point-X, end-point-Y and the rbrr of the end-point of the segment.

All elements of the outline format A list define a segment except the first element that defines the first-point. An outline composed of N segments is described by a list of N+1 elements. A segment is defined by 3 floats if it is a line or 5 floats if it is an arc. The start-point of a segment is never explicitly defined as it is the end-point of the previous segment. If the X and Y coordinates of the end-point of the last segment are equal to the X and Y coordinates of the first-point of the outline, the outline is closed.

rbrr (a.k.a router_bit radius request) defines how cnc25d_api.cnc_cut_outline() must modify a corner:

• if rbrr = 0, the corner is unchanged
• if rbrr > 0, the corner is smoothed to fit the router_bit radius rbrr
• if rbrr < 0, the corner is enlarged to fit the router_bit radius abs(rbrr)

Good practice: If the outline is closed, the rbrr of the last segment must be set to zero. If the outline is open (i.e. not closed), the rbrr of the first-point and the rbrr of the last segment must be set to zero.

The outline format A can be defined with list or tuple. The orientation of a closed outline can be CCW or CW.

outline format A example:

outline_A = [
[  0,  0, 10],            # first-point
[ 50,  0, 15],            # horizontal line
[ 43, 43,  0,  50, 20],   # arc
[  0,  0,  0]]            # vertical line and close the outline

## 4.3. Cnc25D outline format B¶

The Cnc25D outline format B is either a circle or a general outline.

In short, a format-B circle is a list of 3 floats (center-x, center-y, radius). The Cnc25D general outline format B is a list of list of 2 or 4 floats.

The purpose of the Cnc25D general outline format B is to define an outline with points. In the general case, this is a simplification of the outline format A, where the rbrr information is removed.

The first element of the general outline format B list is the first-point. It is defines by a list of 2 floats: X-coordinate, Y-coordinate.

The second element of the general outline format B list is the first segment of the outline. If the first segment is a line, it is defines by a list of 2 floats: end-point-X, end-point-Y. If the first segment is an arc, it is defines by a list of 4 floats: middle-point-X, middle-point-Y, end-point-X, end-point-Y.

All elements of the general outline format B list define a segment except the first element that defines the first-point. An outline composed of N segments is described by a list of N+1 elements. A segment is defined by 2 floats if it is a line or 4 floats if it is an arc. The start-point of a segment is never explicitly defined as it is the end-point of the previous segment. If the X and Y coordinates of the end-point of the last segment are equal to the X and Y coordinates of the first-point of the outline, the outline is closed.

The general outline format B can be defined with list or tuple. The orientation of a closed outline can be CCW or CW.

general outline format B example:

outline_B = [
[  0,  0],            # first-point
[ 50,  0],            # horizontal line
[ 43, 43,  0,  50],   # arc
[  0,  0]]            # vertical line and close the outline

## 4.4. Cnc25D outline format C¶

In short, the Cnc25D outline format C is a list of list of 3 floats.

The purpose of the Cnc25D outline format C is to define a curved-outline with points and tangents. This is an extension of the outline format B, where the tangent inclination is added at each point. This format must be preferred to described a curved-outline.

Each element of the outline format C list is a curve sampling point. It is defines by a list of 3 floats: X-coordinate, Y-coordinate and the tangent inclination angle. The first element of the outline format C list is the first-point. The outline is oriented from the first-point to its last point. The tangent inclination is the angle (included in [-pi, pi]) between the (Ox) direction vector and the oriented curve tangent at the considered sampling point.

The outline format C can be defined with list or tuple.

outline format C example (the X,Y coordinates and the tangent inclination angle are rounded for a better readability):

outline_C = [
[ 10,  0, math.pi/6],    # first-point
[ 20,  5, math.pi/3],
[ 30, 15, math.pi/2],
[ 40, 20, math.pi/4],
[ 50, 22, math.pi/8]]

The Cnc25D outline format C is used as argument by the function cnc25d_api.smooth_outline_c_curve().

If the curved-outline contains one or several inflexion points, it is recommended to chose those points as sampling points. Thus the function cnc25d_api.smooth_outline_c_curve() is able to smooth the entire curved-outline. Otherwise segments containing an inflexion point are leave as line by the function cnc25d_api.smooth_outline_c_curve().

## 4.5. The function Cnc_cut_outline()¶

cnc25d_api. cnc_cut_outline( list, string )
Return a list.

### 4.5.1. cnc_cut_outline purpose¶

If you work with 3-axis CNC, your free XY-path gets actually some constraints due to the router_bit diameter. Real inner angle can not be manufacture and must be replaced either by a smoothed angle or an enlarged angle.

The cnc_cut_outline function aims at converting an outline defined by a list of points into an outline with lines and arcs makable by a 3-axis CNC. For each point, you choose if you want to enlarge the angle, smooth it or leave it sharp.

Look at the CNC Cut Outline Details chapter to get more information on when you should enlarge and when you should smooth a corner angle.

### 4.5.2. cnc_cut_outline usage¶

The cnc_cut_outline() function provides three possibilites as corner transformation: smooth, unchange, enlarge.

If rbrr (a.k.a. router_bit radius request) is positive, the angle is smoothed. If rbrr is negative, the angle is enlarged. If rbrr is zero, the angle is unmodified.

Smoothing a corner is a closed problem: there is only one arc of radius R (= rbrr) that is tangent to the two adjacent segments.

Enlarging a corner is an open problem: there are several arcs of radius R (= rbrr) that can clear the wished outline. Cnc25D chose the arc of radius R (= rbrr) of which the center is on the line defined by the corner-point and the center of the associated smoothed corner. If you want an other solution, you can modify slightly your wished outline (in format A) to influence the final result as shown in the next paragraph alternative enlarged corner.

Notice that the interior of an closed outline is not influencing the process of smoothing or enlarging a corner. Only the local geometry (namely the two adjacent segments) influence this process.

The cnc_cut_outline() function needs as argument an outline of format A and returns an outline of format B. The format B outline can easily be converted into a FreeCAD Part Object, that can be after some conversions be extruded:

my_outline_A = [
[  0.0 ,  0.0,  0.0],   # this corner will be leaved sharp
[ 20.0 ,  0.0,  5.0],   # this corner will be smoothed
[  0.0 , 20.0, -5.0]]   # this corner will be enlarged
my_outline_B = (cnc25d_api.cnc_cut_outline(my_outline_A, "demo_my_outline_A")
my_part_solid = my_part_face.extrude(Base.Vector(0,0,20))

Look at the script cnc25d_api_example.py that you can generate with the executable cnc25d_example_generator.py for a more complete example.

If the requested router_bit radius is too large, the corner transformation may not be applied because of geometrical constraints. You get a warning or error message containing string set as argument. A good practice is to set string to the function name that calls cnc_cut_outline(). So you can find out which outline is not compatible with the requested router_bit radius in case of error. Below an example of warning message due to a too large router_bit radius. Thanks to the string, we know that the outline issue is located in the plank_z_side function:

WARN301: Warning, corner plank_z_side.1 can not be smoothed or enlarged because edges are too short!

### 4.5.3. Alternative enlarged corner¶

As the problematic of enlarging a corner doesn’t have a unique solution, you may want an other enlarging corner than the default one proposed by cnc_cut_outline(). For example, you may want to enlarge a corner without milling one of the adjacent segment. By changing the input outline, you can achieve it:

For comparison, the default result would be:

## 4.6. The function smooth_outline_c_curve()¶

cnc25d_api. smooth_outline_c_curve( list, float, float, string )
Return a list.

It reads a format C outline and returns a format B outline with the following characteristics:

• the outline is made out of arcs
• the outline goes through the sampling points
• the outline tangent at the sampling points has the requested direction (a.k.a. tangent inclination)
• the outline tangent is continuous

With an input format C outline of (N+1) points (i.e. N segement), the function smooth_outline_c_curve() returns a format B outline of 2*N arcs. If a segment contains an inflexion point, the arcs are replace by a line. If input points are aligned or almost aligned, arcs are also replaces by lines.

If the input curve contains inflexion points, choose these points as sampling points. This way, the function smooth_outline_c_curve() can returns an approximated outline containing only arcs. In this case, the outline tangent is continuous along the full path.

To approximate a mathematical or free-hand curve, it is better to use arcs than lines because with arcs you can keep the property of continuous tangent. Most of the 3-axis CNC can handle arcs at the motor driving level. So this function helps you to integrate your curve into a high quality workflow.

float ai_precision: defines the minimal angle to consider that points are not aligned and arcs must be created. Typical value: pi/1000.

flaot ai_router_bit_request: defines the minimal radius of curvature of the returned outline. If a computed arc has a radius smaller than ai_router_bit_request, a warning message is printed without changing the returned outline. Set ai_router_bit_request to your router_bit radius. If you get warnings, create a more regular curve or choose a smaller router_bit.

string ai_error_msg_id: this string is added in the error message and helps you to track bugs.

For more details on the implementation of smooth_outline_c_curve(), read the chapter Smooth Outline Curve Details

## 4.7. The function smooth_outline_b_curve()¶

cnc25d_api. smooth_outline_b_curve( list, float, float, string )
Return a list.

It reads a format B outline and returns a format B outline with the same characteristics as smooth_outline_c_curve().

The function smooth_outline_b_curve() guests the curve tangent at each sampling point according to the previous and following sampling points and then computes the approximated outline with arcs using smooth_outline_c_curve(). The result is poorer than using smooth_outline_c_curve() because the curve tangents are approximated. Use this function only when you can not get the tangent inclinations at the sampling points.

## 4.8. Other outline help functions¶

Cnc25D outline format A and B reduce the description of an outline to the 2D coordinates of points. That’s a drastic reduction of the amount of Data and still keeping the description accurate. But for complex outlines, a large list of point coordinates might become unreadable. It is preferable, to split a large list into comprehensive smaller sub-paths and then concatenate them. Often patterns will be used several times for an outline with some slight modifications like position (of course), scale, mirror or rotation. This is the purpose of the outline help functions.

The outline help functions accept as argument the Cnc25D outline format A and the Cnc25D outline format B and return the outline with the same format:

cnc25d_api.outline_shift_x(outline_AB, x-offset, x-coefficient)
cnc25d_api.outline_shift_y(outline_AB, y-offset, y-coefficient)
cnc25d_api.outline_shift_xy(outline_AB, x-offset, x-coefficient, y-offset, y-coefficient)
cnc25d_api.outline_rotate(outline_AB, center-x, center-y, rotation_angle)
cnc25d_api.outline_close(outline_AB)
cnc25d_api.outline_reverse(outline_AB)

### 4.8.1. outline_shift¶

cnc25d_api. outline_shift_x( list, x-offset, x-factor )
cnc25d_api. outline_shift_y( list, y-offset, y-factor )
cnc25d_api. outline_shift_xy( list, x-offset, x-factor, y-offset, y-factor )
Return a list that defines a sub-sequence of outline.

The definition an outline can be quiet long and tedious. It might be useful to split a long list of points into several small sequences and concatenate them into one big list using the .append() and .extend() methods. Often it happens that sub-sequence patterns appear several times in one outline either shifted or mirrored. The functions outline_shift_x, outline_shift_y and outline_shift_xy can be use to help the reuse of outline sub sequences. Let’s look at the following example.

If we want to define this outline brutally, we must create a list of 28 points. But we can also define first the blue and the green sub-sequences, which are each 3 points and create the complete outline out of them:

# We follow the points in the counter clock wise (CCW)
green_sequence = [
[ 10,  0, 0],
[ 20, 10, 0],
[ 20,  0, 0]]
blue_sequence = [
[  0, 25, 0],
[ 10, 25, 0],
[  0, 20, 0]]
width = 100
height = 80
my_outline = []
my_outline.append([0, 0, 0])
my_outline.extend(blue_sequence)
my_outline.extend(outline_shift_x(blue_sequence, width, -1))
my_outline.append([width, 0, 0])
my_outline.extend(outline_shift_x(green_sequence, width, -1))
my_outline.extend(outline_shift_xy(green_sequence, width, -1, height, -1))
my_outline.append([width, height, 0])
my_outline.extend(outline_shift_xy(blue_sequence, width, -1, height, -1))
my_outline.extend(outline_shift_y(blue_sequence, height, -1))
my_outline.append([0, height, 0])
my_outline.extend(outline_shift_y(green_sequence, height, -1))
my_outline.extend(green_sequence)

This code is easier to maintain.

### 4.8.2. outline_rotate¶

cnc25d_api.outline_rotate(outline_AB, center-x, center-y, rotation_angle)
return outline_AB

It applies a rotation of center (x,y) and angle rotation_angle to each points of the input outline.

### 4.8.3. outline_close¶

cnc25d_api.outline_close(outline_AB)
return outline_AB

If the input outline is open, it closes it with a straight line (from the end-point of the last segment to the first-point).

### 4.8.4. outline_reverse¶

cnc25d_api.outline_reverse(outline_AB)
return outline_AB

It reverses the order of the segments. If the outline is closed, that reverses its orientation (from CCW to CW or opposite). Notice that the .reverse() python method would not return a valid outline (format A or B) because of the first-point and the middle-point of arcs.

## 4.9. ideal_outline()¶

cnc25d_api.ideal_outline(outline-AC, error_mark_string)
return outline-B

The function ideal_outline() lets you quickly convert a format-A or format-C outline into a format-B outline by dropping the additional information contained in the format-A and format-C. The returned format-B outline is probably to suitable for a 3-axis CNC. But you can display this ideal or wished outline in the Tkinter GUI to check the outline construction.