Difference between revisions of "Manual/Plugins/Scripting/0.9.3"

From Knotter
Jump to navigation Jump to search
 
(31 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
{{vbox|0.9.3}}
 +
 
Scripts are in QtScript aka ECMAScript aka JavaScript.  
 
Scripts are in QtScript aka ECMAScript aka JavaScript.  
  
 
The details of the language are specified in the [http://qt-project.org/doc/qt-5.0/qtscript/ecmascript.html Qt ECMAScript reference]. This page focuses on functions and objects specific to Knotter.
 
The details of the language are specified in the [http://qt-project.org/doc/qt-5.0/qtscript/ecmascript.html Qt ECMAScript reference]. This page focuses on functions and objects specific to Knotter.
  
==Global Objects==
+
==Geometry==
  
===point===
+
===Point===
 
A wrapper to [http://qt-project.org/doc/qt-5.0/qtcore/qpointf.html QPointF].
 
A wrapper to [http://qt-project.org/doc/qt-5.0/qtcore/qpointf.html QPointF].
  
Line 12: Line 14:
 
{{object list section|Constructors}}
 
{{object list section|Constructors}}
 
{{object list header}}
 
{{object list header}}
{{object list item|point()|point|{{js|point(0,0)}}}}
+
{{object list item|new Point()|Point|{{js|new Point(0,0)}}}}
{{object list item|point( point other )|line|Copy point {{js|other}}}}
+
{{object list item|new Point( Point other )|Point|Copy point {{js|other}}}}
{{object list item|point( Number x, Number y )|point|Create point with given coordinates}}
+
{{object list item|new Point( Number x, Number y )|Point|Create point with given coordinates}}
  
 
{{object list section|External functions}}
 
{{object list section|External functions}}
 
{{object list header}}
 
{{object list header}}
{{object list item|opposite( point p )|point|{{js|point(-p.x,-p.y)}}}}
+
{{object list item|opposite( Point p )|Point|{{js|new Point(-p.x,-p.y)}}}}
 +
{{object list item|distance(Point a, Point b)|Number|Distance from '''a''' and '''b'''}}
  
 
{{object list end}}
 
{{object list end}}
  
===line===
+
===Line===
 
A wrapper to [http://qt-project.org/doc/qt-5.0/qtcore/qlinef.html QLineF] most of the functionality of '''QLineF''' is also present in {{js|line}}.
 
A wrapper to [http://qt-project.org/doc/qt-5.0/qtcore/qlinef.html QLineF] most of the functionality of '''QLineF''' is also present in {{js|line}}.
  
Line 29: Line 32:
 
{{object list section|Constructors}}
 
{{object list section|Constructors}}
 
{{object list header}}
 
{{object list header}}
{{object list item|line()|line|Empty line}}
+
{{object list item|new Line()|Line|Empty line}}
{{object list item|line( other_line )|line|Copy line {{js|other_line}}}}
+
{{object list item|new Line( Line other )|Line|Copy line {{js|other_line}}}}
{{object list item|line( p1, p2 )|line|Line from point {{js|p1}} to {{js|p2}}}}
+
{{object list item|new Line( point1, point2 )|Line|Line from point {{js|point1}} to {{js|point2}}}}
  
 
{{object list section|Properties}}
 
{{object list section|Properties}}
 
{{object list header}}
 
{{object list header}}
{{object list item|p1|point|Starting point of the line}}
+
{{object list item|p1|Point|Starting point of the line}}
{{object list item|p2|point|End point of the line}}
+
{{object list item|p2|Point|End point of the line}}
 
{{object list item|x1|Number|{{js|p1.x}}}}
 
{{object list item|x1|Number|{{js|p1.x}}}}
 
{{object list item|x2|Number|{{js|p2.x}}}}
 
{{object list item|x2|Number|{{js|p2.x}}}}
Line 44: Line 47:
 
|Angle of the line in degrees. An angle of 0° is a horizontal line pointing to the right.}}
 
|Angle of the line in degrees. An angle of 0° is a horizontal line pointing to the right.}}
 
{{object list item|length|Number|Length of the line (distance between {{js|p1}} and {{js|p2}}}}
 
{{object list item|length|Number|Length of the line (distance between {{js|p1}} and {{js|p2}}}}
 +
{{object list item|dx|Number|{{js|p1.x-p2.x}}}}
 +
{{object list item|dy|Number|{{js|p1.y-p2.y}}}}
  
 
{{object list section|Methods}}
 
{{object list section|Methods}}
 
{{object list header}}
 
{{object list header}}
{{object list item|intersect ( line other )|line|Return the intersection point between the current line and other}}
+
{{object list item|intersect ( Line other )|Point|Return the intersection point between the current line and other}}
{{object list item|normalVector()|line|Returns a line that is perpendicular to this line with the same starting point and length.}}
+
{{object list item|normalVector()|Line|Returns a line that is perpendicular to this line with the same starting point and length.}}
{{object list item|unitVector()|line|Returns the unit vector for this line, i.e a line starting at the same point as this line with a length of 1.0.}}
+
{{object list item|unitVector()|Line|Returns the unit vector for this line, i.e a line starting at the same point as this line with a length of 1.0.}}
{{object list item|pointAt(Number t)|point|Returns the point at the parameterized position specified by t. The function returns the line's start point if t = 0, and its end point if t = 1.}}
+
{{object list item|pointAt(Number t)|Point|Returns the point at the parameterized position specified by t. The function returns the line's start point if t {{=}} 0, and its end point if t {{=}} 1.}}
{{object list item|translate(point off)|void|Translate the line by {{js|off}}}}
+
{{object list item|translate(Point offset)|void|Translate the line by {{js|offset}}}}
 
{{object list item|translate(Number x,Number y)|void|{{js|translate(point(x,y))}}}}
 
{{object list item|translate(Number x,Number y)|void|{{js|translate(point(x,y))}}}}
 
{{object list end}}
 
{{object list end}}
  
===path===
+
===Polygon===
 +
{{object list begin}}
 +
{{object list header}}
 +
{{object list item|new Polygon()|Polygon|Create an empty polygon.}}
 +
{{object list item|new Polygon(vertices)|Polygon|Create a polygon with given vertices.}}
 +
{{object list item|vertices|Array[Point]|Vertices of the polygon.}}
 +
{{object list item|contains(point)|Boolean|Whether the point is inside the polygon.}}
 +
{{object list item|contains(x,y)|Boolean|{{js|contains(new Point(x,y))}}.}}
 +
{{object list item|add_vertex(point)|void|Appends a vertex to {{js|vertices}}.}}
 +
{{object list end}}
 +
 
 +
==Graph==
 +
 
 +
===Graph===
 +
The graph for a given knot.
 +
{{object list begin}}
 +
{{object list header}}
 +
{{object list item|new graph()|Graph|Creates an empty graph}}
 +
{{object list item|nodes|Array[Node]|Nodes in the graph}}
 +
{{object list item|edges|Array[Edge]|Edges in the graph}}
 +
{{object list item|selected_nodes|Array[node]|List of the selected nodes}}
 +
{{object list item|add_node(point)|Node|Creates a new node}}
 +
{{object list item|add_node(x,y)|Node|Creates a new node}}
 +
{{object list item|remove_node(node)|void|Remove node from the graph}}
 +
{{object list item|connect(node1,node2)|Edge|Creates a new edge}}
 +
{{object list item|node_at(point)|Node|Get the node at the given location}}
 +
{{object list item|node_at(x,y)|Node|Get the node at the given location}}
 +
{{object list end}}
 +
 
 +
===Node===
 +
{{object list begin}}
 +
{{object list header}}
 +
{{object list item|pos|Point|Position of the node.}}
 +
{{object list item|x|Number|{{js|pos.x}}.}}
 +
{{object list item|y|Number|{{js|pos.y}}.}}
 +
{{object list item|selected|Boolean|Whether the node is selected.}}
 +
{{object list item|edges|Array[Edge]|(Read-Only) Edges with this node as vertex.}}
 +
{{object list item|has_edge_too(Node other)|Boolean|Whether there is an edge from {{js|this}} to {{js|other}}.}}
 +
{{object list item|edge_to(Node other)|Edge|Edge connecting {{js|this}} and {{js|other}}.}}
 +
{{object list end}}
 +
 
 +
===Edge===
 +
{{object list begin}}
 +
{{object list header}}
 +
{{object list item|vertex1|Node|One of the vertices of the edge}}
 +
{{object list item|vertex2|Node|One of the vertices of the edge}}
 +
{{object list item|line|Line|Line from {{js|vertex1.pos}} to {{js|vertex2.pos}}}}
 +
{{object list item|midpoint|Point|Point at the middle of the edge}}
 +
{{object list item|is_vertex(node)|Boolean|Whether the node is a vertex of the edge}}
 +
{{object list item|other(node)|Node|If the given node is one of its vertices, return the other vertex}}
 +
{{object list end}}
 +
 
 +
==Interaction with Knotter==
 +
 
 +
 
 +
===knotter===
 +
Object with information on Knotter.
 +
{{object list begin}}
 +
{{object list header}}
 +
{{object list item|version|String|Knotter version}}
 +
{{object list item|has_version(Number major,Number minor)|Boolean|Whether the current version is greater than major.minor.0}}
 +
{{object list end}}
 +
 
 +
 
 +
===window===
 +
Perform some basic operations to Knotter main window.
 +
{{object list begin}}
 +
{{object list header}}
 +
{{object list item|current_file|String|(Read only) File name of the knot in the active tab}}
 +
{{object list item|current_tab|Number|Index of the active tab}}
 +
{{object list item|open_tabs|Number|Number of open tabs}}
 +
{{object list item|document|Document|Document corresponding to the current tab.}}
 +
{{object list item|open( String file )|Boolean|Open file, returns true if successful}}
 +
{{object list item|open()|Boolean|Create an new tab}}
 +
{{object list end}}
 +
 
 +
===window.dialog===
 +
An object that contains several functions to display simple dialogs to the user
 +
{{object list begin}}
 +
{{object list header}}
 +
{{object list item|information(message,title{{=}}"")|void|Display an information dialog}}
 +
{{object list item|warning(message,title{{=}}"")|void|Display a warning dialog}}
 +
{{object list item|critical(message,title{{=}}"")|void|Display an error dialog}}
 +
{{object list item|question(message, title{{=}}"", button_0{{=}}"OK", button_1{{=}}"", button_2{{=}}"")|Number|Display a dialog asking a question. For every non-empty button text a button is shown. Returns the index of the button that the user pressed.}}
 +
{{object list item|get_open_file(title{{=}}"",filters{{=}}"")|String|Show a dialog to open a file. Filters is in the form ''"Text (.txt);;Image (.svg .png)"'', Returns the selected file name or an empty string if the user canceled the dialog.}}
 +
{{object list item|get_number(message, title{{=}}"", default_value{{=}}0, min{{=}}MIN, max{{=}}MAX)|Number|Asks a dialog for a number. Returns NaN if the user canceled.}}
 +
{{object list item|get_integer(message, title{{=}}"", default_value{{=}}0, min{{=}}MIN, max{{=}}MAX)|Number|Just like '''get_number''' but only integers values are allowed}}
 +
{{object list item|get_text(message,title{{=}}"",default_value{{=}})|String|Ask the user for a line of text.}}
 +
{{object list item|information(get_item,title{{=}}"",items{{=}}[])|String|Ask the user to select an item from the list. Returns the string representing the value or an empty string if the user canceled the dialog.}}
 +
{{object list item|load_widget(file_name)|QWidget|Load a widget from a Ui file}}
 +
{{object list end}}
 +
 
 +
===Document===
 +
(Global object) The document from which the script was called. While '''window.document''' may change, the global '''document''' object will be the same during the entire script.
 +
{{object list begin}}
 +
{{object list header}}
 +
{{object list item|filename|String|The name of the file for this document.}}
 +
{{object list item|graph|Graph|The graph contained by the document.}}
 +
{{object list item|grid|Grid|The grid used by the document.}}
 +
{{object list item|insert(graph,message{{=}}"ScriptInsert")|Boolean|Insert graph in the document. The inserted graph will have to be placed by the user in the desired location. Returns whether insertion has been successful.}}
 +
{{object list item|begin_macro(message)|void|Wrap following edits to the document in a macro, the message will be the text displayed in the action history. Macros can be nested.}}
 +
{{object list item|end_macro()|void|End current macro. For each call to {{js|begin_macro}} there should be a call to {{js|end_macro}}.}}
 +
{{object list end}}
 +
 
 +
===Grid===
 +
The grid displayed by a document object.
 +
{{object list begin}}
 +
{{object list header}}
 +
{{object list item|size|Number|Size of a grid cell.}}
 +
{{object list item|origin|Point|Position of the grid origin}}
 +
{{object list item|enabled|Boolean|Whether the grid is displayed or not.}}
 +
{{object list item|shape|String|One of ''SQUARE'', ''TRIANGLE1'' or ''TRIANGLE2''.}}
 +
{{object list item|enable()|void|Shorthand for {{js|grid.enabled {{=}} true;}}.}}
 +
{{object list item|disable()|void|Shorthand for {{js|grid.enabled {{=}} false;}}.}}
 +
{{object list end}}
 +
 
 +
===Path===
 
Object used in cusp plugins to draw the knot line, wrapper to the Knotter internal '''Path_Builder''' class.  
 
Object used in cusp plugins to draw the knot line, wrapper to the Knotter internal '''Path_Builder''' class.  
 
Cannot be constructed by the user.
 
Cannot be constructed by the user.
 
{{object list begin}}
 
{{object list begin}}
 
{{object list section|Methods}}
 
{{object list section|Methods}}
{{object list item|add_line( point p1, point p2 )|void|Draw a straight line from {{js|p1}} to {{js|p2}} }}
+
{{object list header}}
{{object list item|add_quad( point p1, point control, point p2|void
+
{{object list item|add_line( Point p1, Point p2 )|void|Draw a straight line from {{js|p1}} to {{js|p2}} }}
 +
{{object list item|add_quad( Point p1, Point control, Point p2|void
 
|Draw a quadratic curve from {{js|p1}} to {{js|p2}} with control point {{js|control}} }}
 
|Draw a quadratic curve from {{js|p1}} to {{js|p2}} with control point {{js|control}} }}
{{object list item|add_cubic( point p1, point control1, point control2, point p2 )|void
+
{{object list item|add_cubic( Point p1, Point control1, Point control2, Point p2 )|void
 
|Draw a cubic curve from {{js|p1}} to {{js|p2}} with control points {{js|control1}} and {{js|control2}} }}
 
|Draw a cubic curve from {{js|p1}} to {{js|p2}} with control points {{js|control1}} and {{js|control2}} }}
 
{{object list end}}
 
{{object list end}}
Line 69: Line 191:
 
==Plugin-specific objects==
 
==Plugin-specific objects==
  
===Cusp===
+
===Cusp Plugin===
 
{{object list begin}}
 
{{object list begin}}
 
{{object list header}}
 
{{object list header}}
 
{{object list item|angle|Number|The angle between input and output edge}}
 
{{object list item|angle|Number|The angle between input and output edge}}
{{object list item|cusp_angle|Number|Style setting, if {{js|angle}} > {{js|cusp_angle}} , draw a cusp}}
+
{{object list item|cusp_angle|Number|Style setting, if {{js|angle > cusp_angle}} , draw a cusp}}
 
{{object list item|handle_length|Number|Style setting, "curve" style parameter in the UI}}
 
{{object list item|handle_length|Number|Style setting, "curve" style parameter in the UI}}
{{object list item|start_handle|line|Starting point for lines, start_handle.p1 will be connected to the path forming the crossing}}
+
{{object list item|start_handle|Line|Starting point for lines, start_handle.p1 will be connected to the path forming the crossing}}
{{object list item|finish_handle|line|Ending point for lines, finish_handle.p1 will be connected to the path forming the crossing}}
+
{{object list item|finish_handle|Line|Ending point for lines, finish_handle.p1 will be connected to the path forming the crossing}}
{{object list item|cusp_point|point|Pre-computed cusp point location}}
+
{{object list item|cusp_point|Point|Pre-computed cusp point location}}
{{object list item|node_point|point|Position of the node between the two edges}}
+
{{object list item|node_point|Point|Position of the node between the two edges}}
{{object list item|input_edge|line|Line corresponding to the input edge}}
+
{{object list item|input_edge|Line|Line corresponding to the input edge}}
{{object list item|output_edge|line|Line corresponding to the output edge}}
+
{{object list item|output_edge|Line|Line corresponding to the output edge}}
{{object list item|path|path|Object used to build the path}}
+
{{object list item|path|Path|Object used to build the path}}
 +
{{object list item|direction|Number| -1 or +1 depending on the direction of the angle (clockwise or counter)}}
 
{{object list end}}
 
{{object list end}}
  
Line 89: Line 212:
 
{{js|start_handle.p2}} and {{js|finish_handle.p2}} may be used as control points.
 
{{js|start_handle.p2}} and {{js|finish_handle.p2}} may be used as control points.
  
If {{js|angle}} > {{js|cusp_angle}} the line should pass through {{js|cusp_point}}
+
If {{js|angle > cusp_angle}} the line should pass through {{js|cusp_point}}
  
 
====Example====
 
====Example====
Line 97: Line 220:
 
{
 
{
 
     // Create a "handle" that on cusp_point with size handle_length to determine the control points
 
     // Create a "handle" that on cusp_point with size handle_length to determine the control points
     handle {{=}} line(start_handle.p1,finish_handle.p1);
+
     handle {{=}} new Line(start_handle.p1,finish_handle.p1);
 
     handle.translate(cusp_point);
 
     handle.translate(cusp_point);
 
     handle.translate(opposite(start_handle.p1));
 
     handle.translate(opposite(start_handle.p1));

Latest revision as of 16:34, 11 June 2013

Scripts are in QtScript aka ECMAScript aka JavaScript.

The details of the language are specified in the Qt ECMAScript reference. This page focuses on functions and objects specific to Knotter.

Geometry

Point

A wrapper to QPointF.

Constructors
Name Type Description
new Point() Point new Point(0,0)
new Point( Point other ) Point Copy point other
new Point( Number x, Number y ) Point Create point with given coordinates
External functions
Name Type Description
opposite( Point p ) Point new Point(-p.x,-p.y)
distance(Point a, Point b) Number Distance from a and b

Line

A wrapper to QLineF most of the functionality of QLineF is also present in line.

Constructors
Name Type Description
new Line() Line Empty line
new Line( Line other ) Line Copy line other_line
new Line( point1, point2 ) Line Line from point point1 to point2
Properties
Name Type Description
p1 Point Starting point of the line
p2 Point End point of the line
x1 Number p1.x
x2 Number p2.x
y1 Number p1.y
y2 Number p2.y
angle Number Angle of the line in degrees. An angle of 0° is a horizontal line pointing to the right.
length Number Length of the line (distance between p1 and p2
dx Number p1.x-p2.x
dy Number p1.y-p2.y
Methods
Name Type Description
intersect ( Line other ) Point Return the intersection point between the current line and other
normalVector() Line Returns a line that is perpendicular to this line with the same starting point and length.
unitVector() Line Returns the unit vector for this line, i.e a line starting at the same point as this line with a length of 1.0.
pointAt(Number t) Point Returns the point at the parameterized position specified by t. The function returns the line's start point if t = 0, and its end point if t = 1.
translate(Point offset) void Translate the line by offset
translate(Number x,Number y) void translate(point(x,y))

Polygon

Name Type Description
new Polygon() Polygon Create an empty polygon.
new Polygon(vertices) Polygon Create a polygon with given vertices.
vertices Array[Point] Vertices of the polygon.
contains(point) Boolean Whether the point is inside the polygon.
contains(x,y) Boolean contains(new Point(x,y)).
add_vertex(point) void Appends a vertex to vertices.

Graph

Graph

The graph for a given knot.

Name Type Description
new graph() Graph Creates an empty graph
nodes Array[Node] Nodes in the graph
edges Array[Edge] Edges in the graph
selected_nodes Array[node] List of the selected nodes
add_node(point) Node Creates a new node
add_node(x,y) Node Creates a new node
remove_node(node) void Remove node from the graph
connect(node1,node2) Edge Creates a new edge
node_at(point) Node Get the node at the given location
node_at(x,y) Node Get the node at the given location

Node

Name Type Description
pos Point Position of the node.
x Number pos.x.
y Number pos.y.
selected Boolean Whether the node is selected.
edges Array[Edge] (Read-Only) Edges with this node as vertex.
has_edge_too(Node other) Boolean Whether there is an edge from this to other.
edge_to(Node other) Edge Edge connecting this and other.

Edge

Name Type Description
vertex1 Node One of the vertices of the edge
vertex2 Node One of the vertices of the edge
line Line Line from vertex1.pos to vertex2.pos
midpoint Point Point at the middle of the edge
is_vertex(node) Boolean Whether the node is a vertex of the edge
other(node) Node If the given node is one of its vertices, return the other vertex

Interaction with Knotter

knotter

Object with information on Knotter.

Name Type Description
version String Knotter version
has_version(Number major,Number minor) Boolean Whether the current version is greater than major.minor.0


window

Perform some basic operations to Knotter main window.

Name Type Description
current_file String (Read only) File name of the knot in the active tab
current_tab Number Index of the active tab
open_tabs Number Number of open tabs
document Document Document corresponding to the current tab.
open( String file ) Boolean Open file, returns true if successful
open() Boolean Create an new tab

window.dialog

An object that contains several functions to display simple dialogs to the user

Name Type Description
information(message,title="") void Display an information dialog
warning(message,title="") void Display a warning dialog
critical(message,title="") void Display an error dialog
question(message, title="", button_0="OK", button_1="", button_2="") Number Display a dialog asking a question. For every non-empty button text a button is shown. Returns the index of the button that the user pressed.
get_open_file(title="",filters="") String Show a dialog to open a file. Filters is in the form "Text (.txt);;Image (.svg .png)", Returns the selected file name or an empty string if the user canceled the dialog.
get_number(message, title="", default_value=0, min=MIN, max=MAX) Number Asks a dialog for a number. Returns NaN if the user canceled.
get_integer(message, title="", default_value=0, min=MIN, max=MAX) Number Just like get_number but only integers values are allowed
get_text(message,title="",default_value=) String Ask the user for a line of text.
information(get_item,title="",items=[]) String Ask the user to select an item from the list. Returns the string representing the value or an empty string if the user canceled the dialog.
load_widget(file_name) QWidget Load a widget from a Ui file

Document

(Global object) The document from which the script was called. While window.document may change, the global document object will be the same during the entire script.

Name Type Description
filename String The name of the file for this document.
graph Graph The graph contained by the document.
grid Grid The grid used by the document.
insert(graph,message="ScriptInsert") Boolean Insert graph in the document. The inserted graph will have to be placed by the user in the desired location. Returns whether insertion has been successful.
begin_macro(message) void Wrap following edits to the document in a macro, the message will be the text displayed in the action history. Macros can be nested.
end_macro() void End current macro. For each call to begin_macro there should be a call to end_macro.

Grid

The grid displayed by a document object.

Name Type Description
size Number Size of a grid cell.
origin Point Position of the grid origin
enabled Boolean Whether the grid is displayed or not.
shape String One of SQUARE, TRIANGLE1 or TRIANGLE2.
enable() void Shorthand for grid.enabled = true;.
disable() void Shorthand for grid.enabled = false;.

Path

Object used in cusp plugins to draw the knot line, wrapper to the Knotter internal Path_Builder class. Cannot be constructed by the user.

Methods
Name Type Description
add_line( Point p1, Point p2 ) void Draw a straight line from p1 to p2
add_quad( Point p1, Point control, Point p2 void Draw a quadratic curve from p1 to p2 with control point control
add_cubic( Point p1, Point control1, Point control2, Point p2 ) void Draw a cubic curve from p1 to p2 with control points control1 and control2

Plugin-specific objects

Cusp Plugin

Name Type Description
angle Number The angle between input and output edge
cusp_angle Number Style setting, if angle > cusp_angle , draw a cusp
handle_length Number Style setting, "curve" style parameter in the UI
start_handle Line Starting point for lines, start_handle.p1 will be connected to the path forming the crossing
finish_handle Line Ending point for lines, finish_handle.p1 will be connected to the path forming the crossing
cusp_point Point Pre-computed cusp point location
node_point Point Position of the node between the two edges
input_edge Line Line corresponding to the input edge
output_edge Line Line corresponding to the output edge
path Path Object used to build the path
direction Number -1 or +1 depending on the direction of the angle (clockwise or counter)

Guidelines

A cusp is expected to render a path from start_handle.p1 to finish_handle.p1.

start_handle.p2 and finish_handle.p2 may be used as control points.

If angle > cusp_angle the line should pass through cusp_point

Example

Follows the code to replicate the built-in rounded cusp.

if ( angle > cusp_angle ) 
{
    // Create a "handle" that on cusp_point with size handle_length to determine the control points
    handle = new Line(start_handle.p1,finish_handle.p1);
    handle.translate(cusp_point);
    handle.translate(opposite(start_handle.p1));
    handle.length = handle_length/2;
    h2 = handle.p2;
    handle.length = -handle_length/2;
    h1 = handle.p2;
    // Use the control points to render the cusp
    path.add_cubic ( start_handle.p1, start_handle.p2, h1, cusp_point );
    path.add_cubic ( finish_handle.p1, finish_handle.p2, h2, cusp_point );
}
else
{
    // Don't draw a cusp, just a cubic curve from start_handle to finish_handle
    path.add_cubic(start_handle.p1,start_handle.p2,finish_handle.p2,finish_handle.p1);
}