Overview
Quick-Mesh (QMSH or qmsh) is a simple, general-purpose procedural-modelling kernel with a high-level imperative geometric scripting language. Quick-Mesh aims to be intuitive (easy-to-use), concise (short and sweet) and flexible (interoperable).
You can use Quick-Mesh as a simple stand-alone scripted CAD system to generate 3D models (polyhedral-mesh). You can also use Quick-Mesh within your own programs and applications as a cross-platform geometric modelling library.
Quick-Mesh scripts are human-readable plain text files stored with the file extension .qmsh. Each QMSH kernel evaluates input scripts and outputs (generates) 3D mesh which can be stored as OBJ, PLY, OFF or STL files. Figure 1.1 provides examples of simple models written in the Quick-Mesh scripting language to help clarify.

Figure 1.1: simple examples of 3D models (rendered above) written in the quick-mesh scripting language (see the .qmsh files below) to help contextualise the input and output of the kernel.
1: return cube - sphere.s(1.25);

1: o = octahedron;
2: return cube - o.duo.s(1.5) & o.s(2.0);

1: return torus(0.01,0.001,64,32).sy(3)
2: - torus(0.011,0.00025,64,16).ly(2,0.00125).cy;

1: return cylinder(0.25,0.5,32).zy
2: + cylinder(0.25,1,32).rz(90)
3: - cylinder(0.2,0.5,32).zy
4: - cylinder(0.2,1,32).rz(90);

1: m = cylinder.s(0.5,3,0.5);
2: return cube + m - m.duo.rz(90) - m.duo.rx(90);

1: return cube(1.05,0.1,1.05)
2: + cube(0.125,1,0.125).nzy.grid(2,1,2,0.9,0,0.9).cxz
3: + cube(0.8,0.1,0.1).tz(0.45).ringy(4).nzy.ty(-0.05).ly(2,-0.75)
4: + cube(0.125,1.25,0.125).zy.lx(2,0.9).cx.tz(-0.45)
5: + cube(1.05,0.1,0.15).t(0,1.25,-0.45)
6: + cube(0.8,0.075,0.075).ty(0.25).ly(4,0.25).tz(-0.45);

Each QMSH script contains a set of statements - which specify modelling operations that define a boundary-representation (a polygon-mesh) of an object. In this manner each script encodes the modelling process (i.e. the set of steps) required to define a mesh rather than the actual geometric elements (vertices/edges/faces). In simple words: each script is an intermediary representation (IR).
QMSH kernels perform two basic operations to create models from scripts:
language-parsing (
parsing for short) and
geometric-assembly (also termed
mesh-assembly or simply
assembly). Figure 1.2 illustrates the behaviour described.
Input
a plain text file with extension .qmsh
Process : QMSH
1 parse → statements in input
2 assemble → output mesh
Output
a 3D model file as:
.obj, .off, .ply or .stl
Input
a plain text file with extension .qmsh
Process : QMSH
1 parse → statements in input
2 assemble → output mesh
Output
a 3D model file as:
.obj, .off, .ply or .stl
Figure 1.2: simple schematic illustrating the general operation of a quick-mesh kernel.
The primary aims, objectives and underlying motivations of QMSH are outlined next.
→
Intuitivescripts should be easy to read, write, automatically generate and parse - essentially the grammar should be simple to understand, highly legible and quick for one to learn.
→
Concisethe kernel and scripting language should be succinct - in particular the build-size of the kernel's executables should be small and the grammar exposed should exhibit brevity - more precisely: the objective is to minimise symbolic redundancy in geometric scripts.
→
Flexiblein terms of its interoperability with pre-existing work-flows, in its ability to construct highly-varied geometric forms and in the versatility of its grammatical constructs.
→
Efficientfrom a computational perspective and from a user-workflow perspective - in particular the requirement for a light-weight streamlined architecture that is suited to use in realtime systems, especially on low-power embedded devices (such as mobiles) under strict memory constraints, and offering a fast and fluid modelling iteration cycle for end-users.
→
Robustto geometric degeneracy and topological artefacts (*up to the limit of double-precision floating-point arithmetic) - in particular stable, reliable (dependable) execution, with consistent meshing results across all supported platforms and device types.
→
Procedural
to its core - in the purest sense of the term - or more plainly fully-automatic, without the reliance on manual interactive editing or non-procedural external assets - capable of expressing all necessary modelling operations functionally - pure proceduralism.
In terms of access: QMSH may be used for free for non-commercial purposes (including research, education and similar not-for-profit endeavours). QMSH may also be used within commercial contexts subject to industrial registration which is available through Codemine. For more information refer to the Terms-of-Use.
Geometric Features
Modelling Techniques, Components and Classes of Operation→
Geometric Primitive Librarya suite of parameterised mesh generating functions - the kernel's
native-geometries:

→
Generalised-Cylinders (3D-Sweeps/Profile-Rails)data-driven procedures for creating custom primitives using various types of generalised-cylinder - including extrusions, revolutions, toroids, sweeps and profile-rails:

→
Euclidean Transformationsfunctions for linear transformations: translating, scaling and rotating geometry - in-particular a short-hand notation for absolute (explicit) and relative (implicit) transforms:
Absolute (Explicit) TransformsTranslate: T(x,y,z), TX(x), TY(y), TZ(z)...
Scale: S(x,y,z), S(f), SX(x), SY(y), SZ(z)...
Rotate: RX(x), RY(y), RZ(z)...
Relative (Implicit) TransformsCenter: C(), CX(), CY(), CZ()...
Zero (To-Origin): Z(), ZX(), ZY(), ZZ()...
Negative-Zero: NZ(), NZX(), NZY(), NZZ()...
→
Instancing Operations (Structured Repetition)functions for generating regular and semi-regular patterns - such as linear, Cartesian grid and radial arrangements - vitally these helpers reduce the need for iterative loops:

→
Boolean-Logic Operations (Constructive Modelling)set-theoretic operations for creating seemingly complex objects as the product of composing simpler primitives - union, difference, intersection and symmetric-difference:

→
Parametric Controlextended numeric and literal types to represent attributed external control parameters - which enable platform and environment agnostic automatic user-interface generation:
1: DBL x(2,0,8,"X-Scale-Factor");
2: DBL y(4,0,8,"Y-Scale-Factor");
↓ ↓ ↓
→
Colourisationfunctions for altering the colours of geometric elements to delineate object components:

→
Modifications, Constructions and Utility-Routinesnon-linear manipulations, deformations and geometric constructions (such as hulls and envelopes), predicates and measures, debugging and profiling functions:

Technical Details: Geometric Facilities and Build PropertiesIn terms of the lower-level technical details of the geometric behaviour and mesh attributes supported by the kernel, QMSH also offers the following:
→
Support for N-Gon (General-Polygon) Meshincluding triangle, quadrilateral, uniform-topology and mixed-topology polygon mesh.
→
Support for Mesh Smoothing-Groupsenables sharp crease/ridge edges to be combined with smooth continuous surfaces.
→
Support for Per-Vertex Analytic RGB-Colour(for mesh debugging) colour-by: normal, valence, declaration-order, operand-id, group-id.
→
Support for Topology-Preserving Minimal-Vertex CSG Operationssuitability to low-polygon-count modelling in resource constrained environments.
→
Support for Parallel Assembly
multi-core simultaneous processing for scalable assembly of larger arrangements.
QMSH runs natively on Linux, Mac-OS and Windows operating systems. QMSH also runs natively on Android mobile devices and as a plugin for the Unity-Engine.
The kernel's pre-built binaries occupy roughly 3.0 MB for each OS. They are distributed as standalone executables - which simply means they do not require installation in order to be run, and that there are no third-party dependencies.
Scripting Language
1: c = cube & sphere(32,16).s(1.4);
2: d = sphere(16,8).s(0.2,0.05,0.2).rgb(0.25);
3: z1 = d.duo.ty(0.5);
4: z2 = d.lx(2,0.4).cx.ry(45).ty(0.5).rz(90);
5: z3 = d.duo.tz(0.2).ringy(3).ty(0.5).rx(90);
6: z4 = d.duo.tz(0.2).ringy(4).ty(0.5).rz(-90);
7: z5 = d.duo + d.gridxz(2,2,0.4,0.4).cxz;
8: z5.ty(0.5).rx(-90);
9: z6 = d.duo.tz(0.25).ringy(6).ty(-0.5);
10: return c - z1 - z2 - z3 - z4 - z5 - z6;

Figure 3.1: a simple script illustrating the use of the qmsh grammar (left) to define a dice (right).
Quick-Mesh’s scripting language aims foremost to be intuitive, concise and flexible.
It derives some of its constructs and semantics from the C-family of programming languages (C, C++, C# and Java) and some from scripting languages such as Javascript, Python and Groovy. Quick-Mesh also introduces a number of original syntactic constructs and grammatical conventions that seek to reduce the number of characters one must type in geometric modelling scripts - whilst simultaneously enhancing legibility and ease of understanding. In essence the Quick-Mesh scripting language is designed to be short and sweet. Further more (as a consequence of this), it is vital to note that Quick-Mesh is not intended to be a general purpose Turing complete programming language. Instead - it seeks only to provide the core (fundamental/axiomatic) facilities for the scripted definition of geometric objects.
Formally the QMSH Scripting Language can be classified as an imperative, closed-form, high-level, object-oriented, procedural geometric DSL - whose primary grammatical construct is the sequential-expression-chain effected with dot-notation semantics. It employs a declaration-order execution-model over bracketed expressions (or precedence-based symbolic operators) and though being strongly typed internally emulates the behaviour of a dynamically typed interpreted grammar.
The next sections provide a quick tour of the key aspects of the QMSH grammar.
Statement TypesPut simply - a statement instructs a kernel's geometric assembler to do something.
There are four key types of statement supported by the scripting language which are outlined in figure 3.2 and in the following break-down for reference.
1: // a parameter-definition statement
2: INT count(4,1,5,"Repeat-Count");
3: // an object-assignment statement
4: o = octahedron.lx(count,1);
5: // a general-action statement
6: o.cx.rgb(0,0.5,1);
7: // the return statement
8: return o;

Figure 3.2: a simple script illustrating the four key types of statement provided by the scripting language for controlling the behaviour of a quick-mesh kernel.
→
Parameter-Definition Statementsdeclare and define public (external) control parameters that drive the modelling process.
→
Object-Assignment Statementsassign private (internal) objects to symbols - these are temporary intermediary objects.
→
General-Action Statementsinvoke operations (that preserve referential integrity) on private (internal) objects.
→
The Return Statement
specifies which object should be the output of the modelling process (the return value).
All statements are terminated by a semicolon (;), and C-style comments (i.e. // for single lines and /* ... */ for multiple lines) may be used to communicate the geometric intent of statements for clarity. Statements can span multiple lines and/or multiple (short) statements can occur on the same line. Note: the only mandatory type of statement in a quick-mesh script is the return statement - all others are optional.
Syntax, Constructs and Language Usability FeaturesThe key concepts, constructs and syntactic sweeteners in the QMSH grammar, that enhance the brevity and legibility of its geometric scripts, are outlined next.
Implicitly Typed Variables
Type-Free (Implicit) Variable-Definitions allow variables to be declared and defined without having to specify a type-name - meaning fewer characters are typed to assign a value or object. This is possible because the kernel can unambiguously resolve the type of script-internal symbols automatically:1: MSH x = cube(); → becomes simply → x = cube();
End. Geometric
Arithmetic
Operators
Geometric Arithmetic Operators
Native Symbolic-Operators for Boolean-Logic allow CSG operations to be expressed in an intuitive manner that reads much like simple arithmetic expressions. This significantly enhances the application of these fundamental set-theoretic constructs by improving their legibility (relative to traditional declarative styled nested or bracketed expressions) and as such improves script tractability:1: return intersect { difference { cube, sphere(1.25) }, sphere(1.4) };
2: ↓ becomes simply ↓
3: return cube - sphere(1.25) & sphere(1.4);
End. Interactive
Control
Parameters
Interactive Control Parameters
Interactive Control Parameters (via Parameter Definition Statements) allow dynamic entity descriptors to easily constructed and manipulated through graphical tools. In-particular they enable level-of-detail model generation, the representation of entity behaviours and the construction of families (i.e. sets of entities that share structural axioms and/or aesthetic styles).
Note: refer to the parameter-definition statement type for more information.
End.
DOIEO:
Declaration-
Order-IS-
Execution-Order
DOIEO: Declaration-Order-IS-Execution-Order
Declaration-Order-IS-Execution-Order
The DOIEO principal results in a grammar that is exceptionally easy to parse. However it can be a source of confusion for new users. As such it is vital to be aware that in Quick-Mesh - (at any given operative scope) the order in which you express generative logic is the order in which it will be executed. This applies not only to geometric expressions but equally to numeric expressions: 1: // in qmsh - the order in which you express operations
2: // is the order in which they are applied - for example:
3:
4: a = 10 - 3 * 2;
5:
6: // ...evaluates to a = 14 and NOT a = 4 because the order
7: // of evaluation maps to ((10-3)*2) rather than (10-(3*2))
8:
9: // although the difference is subtle it is fundamental
10: // to grasp this behaviour to avoid later confusion
See-Also: AOS (Annonymous-Operative-Scopes).
Side-Note: DOIEO (pronounced: 'do-eee-oh') is an odd term to annunciate/vocalise/say in that it has features of both an acronym and initialism.End. PF-DN-SECs:
Method-Chaining
(on Steroids)
PF-DN-SECs: Method-Chaining (on Steroids)
Post-Fix Dot-Notation Sequential-Expression-Chains
Post-Fix Dot-Notation Chaining-Expression Semantics enable sequences of generative operations to be intuitively expressed in left-to-right execution order - this means the declaration-order and evaluation-order are consistent (rather than reversed or inverted):1: return rotateZ(45,translateX(8,scaleY(5,cylinder())));
2: ↓ becomes simply ↓
3: return cylinder().scaleY(5).translateX(8).rotateZ(45);
Specifically: the acronym PF-DN-SEC denotes the use of dot-notation accessors in the quick-mesh grammar to symbolise the ordered concatenation of generative operations.End. Pre-Fix Modifier-Symbols
Pre-Fix Primitive-Modifier Symbols provide handy shortcuts for applying common modificatiions to many of the built-in native geometric primitives - which simultaneously use fewer characters to express and also execute faster than the generalised versions as they support optimised implementations:1: return cube().round(); → becomes simply → return rcube();
Commonly used prefix modifier-symbols in the quick-mesh grammar include:
B | bbevel → beveled (chamfered) edges
R | rround → rounded edges
S | ssub-divde → bi-linearly sub-divided
C | ccapped → capped (omit polar-points)
P | ppolar → polar-pointed (add polar-points)
O | oopen → open (non-cyclic)
M | mmanifold → share-vertex (for platonics)
G | g
gouraud → smooth-shade (for hulls and envelopes)
End. Post-Fix
Axis-Specifiers
(Swizzling)
Post-Fix Axis-Specifiers (Swizzling)
Post-Fix Axis-Specifier Operation Variants simultaneously reduce symbolic redundancy in scripts (by omitting unused arguments), and improve the legibility of transforms and operations that are applied about specific axis (by removing the scope for ambiguity):1: x.translate(0,10,0); → becomes simply → x.translateY(10);
The grammar also exposes exact-angle post-fix specifiers for orthogonal rotations.End. FSR:
Flexible-Symbol-
Resolution
FSR: Flexible-Symbol-Resolution
Case and Underscore Insensitive Native-Symbol Resolution provide the flexibility to express generative logic using a variety of naming conventions. This means that all the built-in functions can be invoked using camel-case, lower-case, upper-case or any-case conventions based on one's preference:1: return cylinder.zeroY;
2: could equally be expressed as:
3: return Cylinder.Zeroy; or...
4: return CYLINDER.ZERO_Y; or even...
5: return CyLinDer.zEroY;
Flexible-Symbol-Resolution also makes it easy to override the built-in native functions without losing access to them or having to fully qualify them to disambiguate one's intentions.End. Native Synonyms (Aliases)
Native Synonym-Support (Shorthands and Aliasing) enable the built-in operations to be invoked using succinct abbreviations - which dramatically reduce the number of characters one must type to express analogous generative logic - this aspect of the grammar underpins the brevity of QMSH scripts:1: return cylinder.scaleY(5).translateX(8).rotateZ(45).ringRepeatY(4);
2: ↓ becomes simply ↓
3: return cylinder.sy(5).tx(8).rz(45).ringy(4);
This relies on uniqueness for/across all native symbol synonyms to ensure ambiguity free resolution.End. Inline Operations
Inline Operations directly mutate (modify) the state of entities to which they are applied. They are particularly helpful for transformations (and similar O(n) linear complexity functions) wherein it would be inefficient to implement such operations in an instantiative manner:1: a = icosahedron(); // ← an instantiative operation
2:
3: a.translate(0,2,0); // ← an inline operation
4: a.rgb(0.25,0.75,0.25); // ← another inline operation
5: return a;
Note: inline operations are the opposite of instantiative operations in quick-mesh.End. Instantiative Operations
Instantiative Operations construct new entities afresh without mutating (modifying) any entities supplied as input. They represent the bulk of the native functions. For example geometric-primitive creation in quick-mesh is instantiative as is structured repetition (instancing), as is CSG using boolean-logic:1: a = rcube(); // ← an instantiative operation
2: b = sphere(); // ← another instantiative operation
3:
4: b.translate(0.25,0.25,0.25); // ← an inline operation
5:
6: c = a - b; // ← a further instantiative operation
7: return c;
Note: instantiative operations are the opposite of inline operations in quick-mesh.End. AOS:
Annonymous-
Operative-
Scopes
AOS: Annonymous-Operative-Scopes
Monolith Annonymous Operative Scopes enable the injection of atomic sub-expressions in statements. They can be particularly helpful when operating within the DOIEO paradigm:1: a = 10 - 3 * 2; // → a = 14
2: ↓ using an annonymous-operative-scope ↓
3: a = 10 - ( 3 * 2 ); // → a = 4
End. IIRR: Immediate-
Intermediary-
Resource-
Release
IIRR: Immediate-Intermediary-Resource-Release
Immediate Intermediary Resource Release ensures that any resources used by temporary entities are immediately released during execution of a script (at sequence-points) as soon as the kernel can guarantee they are no longer accessible. This form of optimal (brute-force) automatic-memory-management (or garbage-collection) is only practical as a product of the high-level nature of the grammar's entities. IIRR is key to enabling the use of the grammar as the complexity of assemblies increases particularly on resource-constrained hardware (such as mobile devices with limited memory).
Note: IIRR is enabled by default and operates silently without the requirement for any intervention.
End.
Flexible
Functions
(FFI + FFD)
Flexible Functions (FFI + FFD)
Flexible Functions describes patterns in the quick-mesh grammar designed to increase the flexibility with which one can wield generative functions in scripts. Specifically it encompasses patterns and constructs enabling flexible function invocation (FFI) and flexible function definition (FFD).
See-Also: FFI (Flexible-Function-Invocation), FFD (Flexible-Function-Definition).
End.
FFI: Flexible
Function
Invocation
FFI: Flexible Function Invocation
Flexible-Function-Invocation is an umbrella term used to describe features of the grammar targeted at enhancing the ease and flexibility with which generative functions may be invoked. This includes:
Flexible Symbol Resolution Automatic Action Promotion Automatic Argument Linearisation
End. FFD: Flexible
Function
Definition
FFD: Flexible Function Definition
Flexible-Function-Definition (or typing-discipline-agnostic function-definition) denotes the ability to exploit varying levels of abstraction in a user-defined function's signature. This enables both high-level (pseudo-code-like) function specifications and lower-level (explicitly-typed) specifications: 1: // as a high-level free(dom) function:
2: genA(w,h,d,f) { ... };
3:
4: // as a conventional typed function:
5: 3D genB(I:width, I:height, I:depth, D:factor) { ... };
6:
7: // as a bounded function:
8: 3D genC(
9: I:width(1,10),
10: I:height(1,10),
11: I:depth(1,10),
12: D:factor(0.0,1.0)
13: ) {
14: ...
15: };
16:
17: // as a hybrid-function:
18: genD(I:w, I:h, I:d, D:f(0.0,1.0)) { ... };
End. AAP:
Automatic
Action
Promotion
AAP: Automatic Action Promotion
Automatic-Action-Promotion (alternatively referred to as the optional use of empty parenthesis) allows zero-argument functions to be automatically treated (invoked) as property getters - which simply means empty brackets after a zero-argument function invocation are optional:1: return cylinder().zeroY(); → becomes simply → return cylinder.zeroY;
End. AAL:
Automatic
Argument
Linearisation
AAL: Automatic Argument Linearisation
Automatic-Argument-Linearisation enables dynamic argument-set reuse across distinct function invocations which supports reducing repetition in scripts. AAL also makes it easier to make revisions to scripts that affect multiple entities simultaneously - and simplifies the expression of relations (i.e. relationships or associative behaviours) between/amongst entities: 1: a = scylinder(2.0,1,32,1,4)
2: - scylinder(1.5,1,32,1,4)
3: + scylinder(1.0,1,32,1,4)
4: - scylinder(0.5,1,32,1,4);
5: return a;
6:
7: ↓ becomes simply ↓
8:
9: p = { 1,32,1,4 };
10: a = scylinder(2.0,p)
11: - scylinder(1.5,p)
12: + scylinder(1.0,p)
13: - scylinder(0.5,p);
14: return a;
Note: AAL is currently supported for all native geometric-primitive generator functions except those that already expect array inputs. AAL support for the grammar's remaining native functions is upcoming.End. auto-return
Automatic-Returns are syntactic sugar that enable one to optionally drop the superfluous return keyword in operative scopes containing a single statement:1: return cube - sphere(1.25);
2: ↓ becomes simply ↓
3: cube - sphere(1.25);
See-Also: auto-terminator.End. auto-terminator
Automatic-Terminators are syntactic sugar that enable one to optionally drop the last statement-delimiting semi-colon in an operative scope:1: cube - sphere(1.25);
2: ↓ becomes simply ↓
3: cube - sphere(1.25)
See-Also: auto-return.End. Generic Entity-Arrays
Generic Entity-Arrays (also termed generic arrays or simply generics) provide dynamic flexible storage for ordered collections of entities of potentially variable or mixed type: 1: a = {
2: cube,
3: { sphere.tx(2), cylinder.tx(-2) },
4: { cone.ty(2), octahedron.ty(-2) },
5: { icosahedron.tz(2), dodecahedron.tz(-2) }
6: };
7: a[0].rgb(0.25);
8: a[1].rgb(0.75,0.25,0.25);
9: a[2].rgb(0.25,0.75,0.25);
10: a[3].rgb(0.25,0.25,0.75);
11: return a;
See-Also: Typesafe-Data-Arrays.End. Typesafe Data-Arrays
Typesafe Data-Arrays (also termed typesafe arrays or simply data arrays) provide static memory-efficient storage for ordered collections of equivalent type primitive values:1: a = D[10]; // creates an empty DBL type data-array with 10 elements
2: b = I[4][5]; // creates an empty 2D INT type data-array
3: c = D{ 3, 5, 7, 11, 13 }; // creates a DBL type data-array with 5 elements
Note: although typesafe arrays are implemented some native functions (that support array inputs) presently require generic-entity-arrays as input. Ubiquitous support for typesafe arrays is upcoming.
See-Also: Generic-Entity-Arrays.End. Kernel Directives
Kernel Directives (also termed simply directives) are metadata statements that are interpreted by an executing environment independently of a script's execution. They are particularly handy for communicating application specific kernel configuration settings.
Note: kernel directives can be roughly thought of as special comments that are directed at implementing kernels rather than at users of the grammar.
End.
Free(dom) Functions
Free(dom) Functions are free (open/abstract) high-level expressions of logic that provide the greatest level of flexibility in the sliding scale of abstraction offered by QMSH's user-defined functions. These are essentially unchecked-generic functions that are free to take on any type, and rely solely on the function author to ensure their validity and correct use: 1: a = cylinder(2.0,1,32)
2: - cylinder(1.5,1,32)
3: + cylinder(1.0,1,32)
4: - cylinder(0.5,1,32);
5: return a;
6:
7: ↓ becomes simply ↓
8:
9: c(r) { cylinder(r,1,32) };
10: return c(2) - c(1.5) + c(1) - c(0.5);
See-Also: Typed-Function, Bounded-Function, Hybrid-Function.End. Typed Functions
Typed Functions resemble typical function specifications in languages that employ a strong static typing discipline (such as C++). In the sliding scale of abstraction (offered by QMSH's user-defined functions) they sit inbetween high-level free-functions and constrained bounded-functions: 1: a = cylinder(2.0,1,32)
2: - cylinder(1.5,1,32)
3: + cylinder(1.0,1,32)
4: - cylinder(0.5,1,32);
5: return a;
6:
7: ↓ becomes simply ↓
8:
9: 3D c(D:radius) { return Cylinder(radius,1,32); };
10: return c(2.0) - c(1.5) + c(1.0) - c(0.5);
See-Also: Freedom-Function, Bounded-Function, Hybrid-Function.End. Bounded Functions
Bounded Functions provide a means to constrain the range of values that input arguments may take: 1: a = cylinder(2.0,1,32)
2: - cylinder(1.5,1,32)
3: + cylinder(1.0,1,32)
4: - cylinder(0.5,1,32);
5: return a;
6:
7: ↓ becomes simply ↓
8:
9: 3D c(D:radius[0.25,5]) { return Cylinder(radius,1,32); };
10: return c(2.0) - c(1.5) + c(1.0) - c(0.5);
See-Also: Freedom-Function, Typed-Function, Hybrid-FunctionEnd. Hybrid Functions
Hybrid Functions combine varying typing-mechanisms within a single function definition. They enable one to mix-and-match (or pix-and-mix) components from freedom, typed and bounded definitions:1: // a partially-typed and partially-bounded function
2: 3D gen(size, D:factor[0.05,0.25], I:steps[2,8]) {
3: return
4: RCUBE(size,size*factor,steps)
5: - BCUBE(size,size*factor);
6: };
7: return gen(1.23,0.125,4);
Note: in the hybridisation of a function's typing-discipline - the key grammatical rule (or requirement) to remember is that if you specify bounds for an argument - you must also specify the argument's type.
See-Also: Freedom-Function, Typed-Function, Bounded-FunctionEnd. Nested Functions
Nested Functions enable the definition of temporary functions bound to an operative scope - which can be helpful for encapsulation. They can be free, typed, bounded or hybrid: 1: 3D gen() {
2: // a nested freedom function
3: subA { dodecahedron.rgb(0.25,0.75,0.25) };
4: // a nested typed function
5: 3D subB() { return octahedron(); };
6: // a nested hybrid function
7: .subC( 3D:i, I:n[2,16] ) { i.tx(-2.5).ringy(n) };
8: // invoke the nested functions
9: return subA + subB.subC(8);
10: };
11: return gen;
End. Implicitly Typed Variables
Implicitly Typed Variables
Type-Free (Implicit) Variable-Definitions allow variables to be declared and defined without having to specify a type-name - meaning fewer characters are typed to assign a value or object. This is possible because the kernel can unambiguously resolve the type of script-internal symbols automatically:1: MSH x = cube(); → becomes simply → x = cube();
End. Geometric Arithmetic Operators
Geometric Arithmetic Operators
Native Symbolic-Operators for Boolean-Logic allow CSG operations to be expressed in an intuitive manner that reads much like simple arithmetic expressions. This significantly enhances the application of these fundamental set-theoretic constructs by improving their legibility (relative to traditional declarative styled nested or bracketed expressions) and as such improves script tractability:1: return intersect { difference { cube, sphere(1.25) }, sphere(1.4) };
2: ↓ becomes simply ↓
3: return cube - sphere(1.25) & sphere(1.4);
End. Interactive Control Parameters
Interactive Control Parameters
Interactive Control Parameters (via Parameter Definition Statements) allow dynamic entity descriptors to easily constructed and manipulated through graphical tools. In-particular they enable level-of-detail model generation, the representation of entity behaviours and the construction of families (i.e. sets of entities that share structural axioms and/or aesthetic styles).
Note: refer to the parameter-definition statement type for more information.
End.
DOIEO: Declaration-Order-IS-Execution-Order
DOIEO: Declaration-Order-IS-Execution-Order
Declaration-Order-IS-Execution-Order
The DOIEO principal results in a grammar that is exceptionally easy to parse. However it can be a source of confusion for new users. As such it is vital to be aware that in Quick-Mesh - (at any given operative scope) the order in which you express generative logic is the order in which it will be executed. This applies not only to geometric expressions but equally to numeric expressions: 1: // in qmsh - the order in which you express operations
2: // is the order in which they are applied - for example:
3:
4: a = 10 - 3 * 2;
5:
6: // ...evaluates to a = 14 and NOT a = 4 because the order
7: // of evaluation maps to ((10-3)*2) rather than (10-(3*2))
8:
9: // although the difference is subtle it is fundamental
10: // to grasp this behaviour to avoid later confusion
See-Also: AOS (Annonymous-Operative-Scopes).
Side-Note: DOIEO (pronounced: 'do-eee-oh') is an odd term to annunciate/vocalise/say in that it has features of both an acronym and initialism.End. PF-DN-SECs: Method-Chaining (on Steroids)
PF-DN-SECs: Method-Chaining (on Steroids)
Post-Fix Dot-Notation Sequential-Expression-Chains
Post-Fix Dot-Notation Chaining-Expression Semantics enable sequences of generative operations to be intuitively expressed in left-to-right execution order - this means the declaration-order and evaluation-order are consistent (rather than reversed or inverted):1: return rotateZ(45,translateX(8,scaleY(5,cylinder())));
2: ↓ becomes simply ↓
3: return cylinder().scaleY(5).translateX(8).rotateZ(45);
Specifically: the acronym PF-DN-SEC denotes the use of dot-notation accessors in the quick-mesh grammar to symbolise the ordered concatenation of generative operations.End. Pre-Fix Modifier-Symbols
Pre-Fix Primitive-Modifier Symbols provide handy shortcuts for applying common modificatiions to many of the built-in native geometric primitives - which simultaneously use fewer characters to express and also execute faster than the generalised versions as they support optimised implementations:1: return cube().round(); → becomes simply → return rcube();
Commonly used prefix modifier-symbols in the quick-mesh grammar include:
B | bbevel → beveled (chamfered) edges
R | rround → rounded edges
S | ssub-divde → bi-linearly sub-divided
C | ccapped → capped (omit polar-points)
P | ppolar → polar-pointed (add polar-points)
O | oopen → open (non-cyclic)
M | mmanifold → share-vertex (for platonics)
G | g
gouraud → smooth-shade (for hulls and envelopes)
End. Post-Fix Axis-Specifiers (Swizzling)
Post-Fix Axis-Specifiers (Swizzling)
Post-Fix Axis-Specifier Operation Variants simultaneously reduce symbolic redundancy in scripts (by omitting unused arguments), and improve the legibility of transforms and operations that are applied about specific axis (by removing the scope for ambiguity):1: x.translate(0,10,0); → becomes simply → x.translateY(10);
The grammar also exposes exact-angle post-fix specifiers for orthogonal rotations.End. FSR: Flexible-Symbol-Resolution
FSR: Flexible-Symbol-Resolution
Case and Underscore Insensitive Native-Symbol Resolution provide the flexibility to express generative logic using a variety of naming conventions. This means that all the built-in functions can be invoked using camel-case, lower-case, upper-case or any-case conventions based on one's preference:1: return cylinder.zeroY;
2: could equally be expressed as:
3: return Cylinder.Zeroy; or...
4: return CYLINDER.ZERO_Y; or even...
5: return CyLinDer.zEroY;
Flexible-Symbol-Resolution also makes it easy to override the built-in native functions without losing access to them or having to fully qualify them to disambiguate one's intentions.End. Native Synonyms (Aliases)
Native Synonyms (Aliases)
Native Synonym-Support (Shorthands and Aliasing) enable the built-in operations to be invoked using succinct abbreviations - which dramatically reduce the number of characters one must type to express analogous generative logic - this aspect of the grammar underpins the brevity of QMSH scripts:1: return cylinder.scaleY(5).translateX(8).rotateZ(45).ringRepeatY(4);
2: ↓ becomes simply ↓
3: return cylinder.sy(5).tx(8).rz(45).ringy(4);
This relies on uniqueness for/across all native symbol synonyms to ensure ambiguity free resolution.End. Inline Operations
Inline Operations directly mutate (modify) the state of entities to which they are applied. They are particularly helpful for transformations (and similar O(n) linear complexity functions) wherein it would be inefficient to implement such operations in an instantiative manner:1: a = icosahedron(); // ← an instantiative operation
2:
3: a.translate(0,2,0); // ← an inline operation
4: a.rgb(0.25,0.75,0.25); // ← another inline operation
5: return a;
Note: inline operations are the opposite of instantiative operations in quick-mesh.End. Instantiative Operations
Instantiative Operations construct new entities afresh without mutating (modifying) any entities supplied as input. They represent the bulk of the native functions. For example geometric-primitive creation in quick-mesh is instantiative as is structured repetition (instancing), as is CSG using boolean-logic:1: a = rcube(); // ← an instantiative operation
2: b = sphere(); // ← another instantiative operation
3:
4: b.translate(0.25,0.25,0.25); // ← an inline operation
5:
6: c = a - b; // ← a further instantiative operation
7: return c;
Note: instantiative operations are the opposite of inline operations in quick-mesh.End. AOS: Annonymous-Operative-Scopes
AOS: Annonymous-Operative-Scopes
Monolith Annonymous Operative Scopes enable the injection of atomic sub-expressions in statements. They can be particularly helpful when operating within the DOIEO paradigm:1: a = 10 - 3 * 2; // → a = 14
2: ↓ using an annonymous-operative-scope ↓
3: a = 10 - ( 3 * 2 ); // → a = 4
End. IIRR: Immediate-Intermediary-Resource-Release
IIRR: Immediate-Intermediary-Resource-Release
Immediate Intermediary Resource Release ensures that any resources used by temporary entities are immediately released during execution of a script (at sequence-points) as soon as the kernel can guarantee they are no longer accessible. This form of optimal (brute-force) automatic-memory-management (or garbage-collection) is only practical as a product of the high-level nature of the grammar's entities. IIRR is key to enabling the use of the grammar as the complexity of assemblies increases particularly on resource-constrained hardware (such as mobile devices with limited memory).
Note: IIRR is enabled by default and operates silently without the requirement for any intervention.
End.
Flexible Functions (FFI + FFD)
Flexible Functions (FFI + FFD)
Flexible Functions describes patterns in the quick-mesh grammar designed to increase the flexibility with which one can wield generative functions in scripts. Specifically it encompasses patterns and constructs enabling flexible function invocation (FFI) and flexible function definition (FFD).
See-Also: FFI (Flexible-Function-Invocation), FFD (Flexible-Function-Definition).
End.
FFI: Flexible Function Invocation
FFI: Flexible Function Invocation
Flexible-Function-Invocation is an umbrella term used to describe features of the grammar targeted at enhancing the ease and flexibility with which generative functions may be invoked. This includes:
Flexible Symbol Resolution Automatic Action Promotion Automatic Argument Linearisation
End. FFD: Flexible Function Definition
FFD: Flexible Function Definition
Flexible-Function-Definition (or typing-discipline-agnostic function-definition) denotes the ability to exploit varying levels of abstraction in a user-defined function's signature. This enables both high-level (pseudo-code-like) function specifications and lower-level (explicitly-typed) specifications: 1: // as a high-level free(dom) function:
2: genA(w,h,d,f) { ... };
3:
4: // as a conventional typed function:
5: 3D genB(I:width, I:height, I:depth, D:factor) { ... };
6:
7: // as a bounded function:
8: 3D genC(
9: I:width(1,10),
10: I:height(1,10),
11: I:depth(1,10),
12: D:factor(0.0,1.0)
13: ) {
14: ...
15: };
16:
17: // as a hybrid-function:
18: genD(I:w, I:h, I:d, D:f(0.0,1.0)) { ... };
End. AAP: Automatic Action Promotion
AAP: Automatic Action Promotion
Automatic-Action-Promotion (alternatively referred to as the optional use of empty parenthesis) allows zero-argument functions to be automatically treated (invoked) as property getters - which simply means empty brackets after a zero-argument function invocation are optional:1: return cylinder().zeroY(); → becomes simply → return cylinder.zeroY;
End. AAL: Automatic Argument Linearisation
AAL: Automatic Argument Linearisation
Automatic-Argument-Linearisation enables dynamic argument-set reuse across distinct function invocations which supports reducing repetition in scripts. AAL also makes it easier to make revisions to scripts that affect multiple entities simultaneously - and simplifies the expression of relations (i.e. relationships or associative behaviours) between/amongst entities: 1: a = scylinder(2.0,1,32,1,4)
2: - scylinder(1.5,1,32,1,4)
3: + scylinder(1.0,1,32,1,4)
4: - scylinder(0.5,1,32,1,4);
5: return a;
6:
7: ↓ becomes simply ↓
8:
9: p = { 1,32,1,4 };
10: a = scylinder(2.0,p)
11: - scylinder(1.5,p)
12: + scylinder(1.0,p)
13: - scylinder(0.5,p);
14: return a;
Note: AAL is currently supported for all native geometric-primitive generator functions except those that already expect array inputs. AAL support for the grammar's remaining native functions is upcoming.End. auto-return
Automatic-Returns are syntactic sugar that enable one to optionally drop the superfluous return keyword in operative scopes containing a single statement:1: return cube - sphere(1.25);
2: ↓ becomes simply ↓
3: cube - sphere(1.25);
See-Also: auto-terminator.End. auto-terminator
Automatic-Terminators are syntactic sugar that enable one to optionally drop the last statement-delimiting semi-colon in an operative scope:1: cube - sphere(1.25);
2: ↓ becomes simply ↓
3: cube - sphere(1.25)
See-Also: auto-return.End. Generic Entity-Arrays
Generic Entity-Arrays (also termed generic arrays or simply generics) provide dynamic flexible storage for ordered collections of entities of potentially variable or mixed type: 1: a = {
2: cube,
3: { sphere.tx(2), cylinder.tx(-2) },
4: { cone.ty(2), octahedron.ty(-2) },
5: { icosahedron.tz(2), dodecahedron.tz(-2) }
6: };
7: a[0].rgb(0.25);
8: a[1].rgb(0.75,0.25,0.25);
9: a[2].rgb(0.25,0.75,0.25);
10: a[3].rgb(0.25,0.25,0.75);
11: return a;
See-Also: Typesafe-Data-Arrays.End. Typesafe Data-Arrays
Typesafe Data-Arrays (also termed typesafe arrays or simply data arrays) provide static memory-efficient storage for ordered collections of equivalent type primitive values:1: a = D[10]; // creates an empty DBL type data-array with 10 elements
2: b = I[4][5]; // creates an empty 2D INT type data-array
3: c = D{ 3, 5, 7, 11, 13 }; // creates a DBL type data-array with 5 elements
Note: although typesafe arrays are implemented some native functions (that support array inputs) presently require generic-entity-arrays as input. Ubiquitous support for typesafe arrays is upcoming.
See-Also: Generic-Entity-Arrays.End. Kernel Directives
Kernel Directives (also termed simply directives) are metadata statements that are interpreted by an executing environment independently of a script's execution. They are particularly handy for communicating application specific kernel configuration settings.
Note: kernel directives can be roughly thought of as special comments that are directed at implementing kernels rather than at users of the grammar.
End.
Free(dom) Functions
Free(dom) Functions are free (open/abstract) high-level expressions of logic that provide the greatest level of flexibility in the sliding scale of abstraction offered by QMSH's user-defined functions. These are essentially unchecked-generic functions that are free to take on any type, and rely solely on the function author to ensure their validity and correct use: 1: a = cylinder(2.0,1,32)
2: - cylinder(1.5,1,32)
3: + cylinder(1.0,1,32)
4: - cylinder(0.5,1,32);
5: return a;
6:
7: ↓ becomes simply ↓
8:
9: c(r) { cylinder(r,1,32) };
10: return c(2) - c(1.5) + c(1) - c(0.5);
See-Also: Typed-Function, Bounded-Function, Hybrid-Function.End. Typed Functions
Typed Functions resemble typical function specifications in languages that employ a strong static typing discipline (such as C++). In the sliding scale of abstraction (offered by QMSH's user-defined functions) they sit inbetween high-level free-functions and constrained bounded-functions: 1: a = cylinder(2.0,1,32)
2: - cylinder(1.5,1,32)
3: + cylinder(1.0,1,32)
4: - cylinder(0.5,1,32);
5: return a;
6:
7: ↓ becomes simply ↓
8:
9: 3D c(D:radius) { return Cylinder(radius,1,32); };
10: return c(2.0) - c(1.5) + c(1.0) - c(0.5);
See-Also: Freedom-Function, Bounded-Function, Hybrid-Function.End. Bounded Functions
Bounded Functions provide a means to constrain the range of values that input arguments may take: 1: a = cylinder(2.0,1,32)
2: - cylinder(1.5,1,32)
3: + cylinder(1.0,1,32)
4: - cylinder(0.5,1,32);
5: return a;
6:
7: ↓ becomes simply ↓
8:
9: 3D c(D:radius[0.25,5]) { return Cylinder(radius,1,32); };
10: return c(2.0) - c(1.5) + c(1.0) - c(0.5);
See-Also: Freedom-Function, Typed-Function, Hybrid-FunctionEnd. Hybrid Functions
Hybrid Functions combine varying typing-mechanisms within a single function definition. They enable one to mix-and-match (or pix-and-mix) components from freedom, typed and bounded definitions:1: // a partially-typed and partially-bounded function
2: 3D gen(size, D:factor[0.05,0.25], I:steps[2,8]) {
3: return
4: RCUBE(size,size*factor,steps)
5: - BCUBE(size,size*factor);
6: };
7: return gen(1.23,0.125,4);
Note: in the hybridisation of a function's typing-discipline - the key grammatical rule (or requirement) to remember is that if you specify bounds for an argument - you must also specify the argument's type.
See-Also: Freedom-Function, Typed-Function, Bounded-FunctionEnd. Nested Functions
Nested Functions enable the definition of temporary functions bound to an operative scope - which can be helpful for encapsulation. They can be free, typed, bounded or hybrid: 1: 3D gen() {
2: // a nested freedom function
3: subA { dodecahedron.rgb(0.25,0.75,0.25) };
4: // a nested typed function
5: 3D subB() { return octahedron(); };
6: // a nested hybrid function
7: .subC( 3D:i, I:n[2,16] ) { i.tx(-2.5).ringy(n) };
8: // invoke the nested functions
9: return subA + subB.subC(8);
10: };
11: return gen;
End. Independently each of these language constructs is incredibly simple - both from a conceptual viewpoint and from the practical perspective of actually implementing them. Indeed when considered in isolation each has limited utility. Yet when one combines these notational devices - under the banner of a geometric DSL - their cumulative power out-weighs the mere summation of their parts. In-particular they reduce the complexity and length of procedural modelling scripts relative to pre-existing languages. To help clarify the following examples indicate the relative decrease in code complexity and script length facilitated by the QMSH grammar.
Comparing Languages: OpenSCAD to Quick-MeshFigure 3.3: examples of simple models defined procedurally - illustrating (from left to right): sphere_minus_cylinders, bandstand and openscad_legacy_example003.
The first example (sphere_minus_cylinders - see figure 3.4) indicates the benefits of an imperative grammar relative to a declarative grammar in terms of the former's ability to simplify script syntax. Note: in particular the linearity of the imperative approach relative to the tree-like structure of the declarative approach.
Open-SCAD
(.scad)
1: module sphere_minus_cylinders() {
2: N = 16; // 32, 64, 96, 128, 192
3: difference() {
4: $fn = N;
5: sphere(6);
6: cube(9, center=true);
7: cylinder(h=20, r=2, center=true);
8: rotate([90,0,0]) cylinder(h=20, r=2, center=true);
9: rotate([0,90,0]) cylinder(h=20, r=2, center=true);
10: }
11: } sphere_minus_cylinders();
Quick-Mesh
(.qmsh)
1: N = 16; // 32, 64, 96, 128, 192
2: return sphere(N,N/2).s(12)
3: - cube.s(9)
4: - cylinder(2,20,N)
5: - cylinder(2,20,N).rx(90)
6: - cylinder(2,20,N).rz(90);
7:
8:
9:
10:
11:

Figure 3.4: comparing Open-SCAD's (left) and QMSH's (right) grammar
The next example (bandstand - see figure 3.5) indicates the advantages of qmsh's instancing (structured repetition) routines - in coordinating common tasks such as constructing a polar arrangement. Note: (in particular) the manner in which the vertical columns are defined in Open-SCAD (lines 9-12) and in QMSH (lines 3-4).
Open-SCAD
(.scad)
1: module bandstand() {
2: $fn = 32;
3: translate([0,0,-120]) {
4: difference() {
5: cylinder(h=50, r=100);
6: translate([0,0,10]) cylinder(h=50, r=90);
7: translate([100,0,35]) cube(50,center);
8: }
9: for (i = [0:5]) {
10: translate([sin(360*i/6)*80,
11: cos(360*i/6)*80,0])
12: cylinder(h=200, r=10);
13: }
14: translate([0,0,200])
15: cylinder(h=80, r1=120, r2=0);
16: }
17: } bandstand();
Quick-Mesh
(.qmsh)
1: N = 32;
2: b = cylinder(100,50,N).zy;
3: c = cylinder(10,200,N)
4: .zy.tx(80).ringy(6);
5: h = cylinder(90,50,N).zy.ty(10)
6: + cube(50,50,100).zyz.ty(10);
7: r = cone(120,80,N).zy.ty(200);
8: return b - h + c + r;
9:
10:
11:
12:
13:
14:
15:
16:
17:

Figure 3.5: syntactic comparison: bandstand model expressed in Open-SCAD's grammar (left) and in QMSH's grammar (right)
The last comparative example (openscad_legacy_example003 - fig. 3.6) demonstrates the effect that qmsh's syntactic constructs (for minimising symbolic redundancy) have in primitive instantiation and in boolean logic operations.
Open-SCAD
(.scad)
1: module openscad_legacy_example003() {
2: difference() {
3: union() {
4: cube([30,30,30], center=true);
5: cube([40,15,15], center=true);
6: cube([15,40,15], center=true);
7: cube([15,15,40], center=true);
8: }
9: union() {
10: cube([50,10,10], center=true);
11: cube([10,50,10], center=true);
12: cube([10,10,50], center=true);
13: }
14: }
15: } openscad_legacy_example003();
Quick-Mesh
(.qmsh)
1: a = cube(30)
2: + cube(40,15,15)
3: + cube(15,40,15)
4: + cube(15,15,40)
5: ;
6: b = cube(50,10,10)
7: + cube(10,50,10)
8: + cube(10,10,50)
9: ;
10: return a - b;
11:
12:
13:
14:
15:

Figure 3.6: comparing Open-SCAD's (left) and QMSH's (right) grammar
***
These simple examples should provide an overall sense of the appearance of scripts written in the Quick-Mesh grammar - relative to a venerable pre-existing grammar.
Mobile-Editor
Quick-Mesh's Mobile-Editor is a free-to-use stand-alone application that exposes the kernel's runtime geometric scripting language in the form of a sand-boxed IDE (integrated development environment): which includes components for script-editing, parsing and mesh-assembly, rendering and visualisation, documentation and IO.
Figure 4.1: screenshots of the qmsh mobile-editor running on android - depicting (from left to right): the procedural-editor (the app's main input component), the geometry-viewer (for visualising and debugging the output mesh), the app's embedded documentation and the options and settings control.
This self-contained system defines an end-to-end work-flow for scripted procedural mesh creation that is intuitive and accessible to all. If you are new to procedural modelling or want to try QMSH quickly, without commitment, and without a steep learning curve, then the Mobile-Editor is the best place to start.
Use the link above to download the mobile-editor's latest release APK V:0.2.3.
Note: an earlier version of the mobile-editor (V:0.1.7) is also available via Google Play - however in light of recent changes in Play-Store policy it is unclear at present as to when an updated version of the editor shall appear on the Play-Store.
Note: ensure you have read and understood the Terms-of-Use before downloading.
Desktop-Kernel
Quick-Mesh's Desktop-Kernel is a free-to-use stand-alone, cross-platform, command-line program that implements the geometric scripting language defined by QMSH. Written in C++, these lower-level tools provide reference implementations of the QMSH kernel for developers, technicians and engineers that can be invoked as any system process - either directly from the command-line or from within user-written programs using standard system calls. Note: the desktop kernel does not have a graphical user-interface - it is essentially a geometric compiler.
An experimental build of the command-line kernel compatible with the Raspberry-Pi operating system - is also provided for educators, researchers and engineers.
Additionally - a universal build of the quick-mesh kernel for Android is provided to simplify use of the grammar with an external editor on machines and devices for which terminal access and command-line invocation are generally prohibited. Note: the universal Android build includes a minimalistic user-interface for the kernel.
Note: ensure you have read and understood the Terms-of-Use before downloading.
Documentation
The following links provide access to the kernel's PDF documentation:
Note: ensure you have read and understood the Terms-of-Use before downloading.
→
Mobile-Editor : Quick-Start GuideInstructions explaining the use of the mobile-editor - this guide documents the components and behaviour of the app's user-interface - and is visually orientated with figures and diagrams to support comprehension.
Note: that the app provides in-depth embedded documentation that also covers the functions in the scripting language.
→
Scripting Language : Quick-Look Summary-SheetA conference-style A1 reference poster (as 2 side-by-side A2 posters) that summarises the geometric grammar defined by QMSH - this is designed to help new users quickly become acquainted/conversant with the key functions in the scripting language.
→
Desktop-Kernel : Quick-Start GuideInstructions explaining the use of the desktop-kernel - this guide specifies the supported command-line options for controlling the operation of the kernel's assembler - with clarifying examples of invocation from the terminal and from within user-programs (via system-calls).
Note: this is a technical guide for advanced users - and does not cover the basics of the scripting language - readers should already be familiar with the grammar.
→
Engine-Plugin : Quick-Start GuideInstructions explaining the use of the engine-plugin - this guide deals with the process of invoking the kernel from within frameworks and engines both ahead-of-time (offline - i.e. at build/compile/design time) and dynamically at runtime.
Note: again that this is a technical guide targeted at advanced users and does not cover the basics of the geometric grammar - readers are expected to be familiar with the kernel.
Note: ensure you have read and understood the Terms-of-Use before downloading.
Additionally: an online version of the public-working-draft of the user reference manual for the quick-mesh scripting language is available via the following link.
Note also that the periodically updated
QMSH Video Documentation Repository includes tutorial videos and application previews to assist new mesh-makers.
Example Scripts
The following examples demonstrate simple 3D entities expressed in the quick-mesh scripting language. Select an image to display the corresponding script.
Example-Script: 'axis_tubes_intersect.qmsh'
axis_tubes_intersect.qmsh
axis_tubes_intersect.qmsh 1: f = cylinder(0.25,2,32)
2: - cylinder(0.2,2,32);
3: return f & f.duo.rx(90);
Example-Script: 'linear_repeat_detail_tube.qmsh'
linear_repeat_detail_tube.qmsh
linear_repeat_detail_tube.qmsh 1: c = cylinder(0.5,5,32);
2: d = torus(0.5,0.125,32,16).ly(11,0.5).cy;
3: e = cylinder(0.25,5.25,32);
4: return c - d - e;
Example-Script: 'doorstop.qmsh'
doorstop.qmsh
1: clip = cube.sz(0.25)
2: + cylinder.s(0.25,1,0.25).tx(-0.5);
3: slant = wedge.zy.s(1.25,0.5,0.25).tx(-0.25)
4: + cube.nzy.s(1.25,0.05,0.25).tx(-0.25);
5: hole = cylinder.s(0.2,1,0.2).tx(-0.5);
6: ret = clip & slant - hole;
7: return ret.sy(0.5).cxyz;
Example-Script: 'sphere_axis_discs.qmsh'
sphere_axis_discs.qmsh
1: c = cube(1.5,0.05,1.5).ly(3,0.125).cy;
2: return c + c.duo.rx(90) + c.duo.rz(90)
3: & sphere(1.25) + sphere;
Example-Script: 'abstract_energy_capsule.qmsh'
abstract_energy_capsule.qmsh
abstract_energy_capsule.qmsh 1: r = capsule(0.25,2,32,16).rgb(0.5,0.525,0.55)
2: + cylinder(0.275,0.125,32).ly(4,0.5).cy.rgb(0.25)
3: - capsule(0.125,1,32,16).sx(0.2).tx(0.25)
4: .ringy(4).rgb(0.85,0.875,0.9);
5: c = cone(0.05,0.5,16).zy.t(0.25,0.875,0)
6: .ringy(8).ry(360.0/16).rgb(0.5,0.75,1);
7: return r - c - c.duo.rz(180);
Example-Script: 'mechanical_gear_A.qmsh'
mechanical_gear_A.qmsh
1: c = cylinder(1,0.1,32);
2: t = torus(1,0.05,32,16);
3: m = c+t;
4: i = cylinder.s(0.5).tz(1.025).ringy(8);
5: o = cylinder.s(0.25).tz(0.5)
6: .ry(180.0/8).ringy(8);
7: b = cube(0.5,1,0.05).tx(-0.5)
8: .ry(180.0/8).ringy(8);
9: h = cylinder(0.25,1,8);
10: return m - i - o - b - h;
Example-Script: 'mechanical_gear_B.qmsh'
mechanical_gear_B.qmsh
1: a = sphere.s(10,0.5,10).rgb(0.5,0.55,0.6);
2: s = sphere(16,8).s(1.5);
3: b = s.duo.tZ(5).ringY(16).rgb(0,0.5,1);
4: c = s.duo.tZ(2.25).ringY(8).rgb(0,0.5,1);
5: d = cone(16).s(0.5).rX(180).rgb(0.5)
6: .t(0,0.25,3.5).ringY(16);
7: e = cone(8).s(0.5).rX(180).rgb(0.5,0,1)
8: .t(0,0.25,1.25).ringY(8);
9: f = torus(3.5,0.125,32,8).tY(0.25).rgb(1);
10: g = torus(1,0.125,16,4).tY(0.25).rgb(1);
11: return a - b - c - d - e - f - g;
Example-Script: 'short_table.qmsh'
short_table.qmsh
1: b = 0.0025;
2: legs = bcube(0.05,0.425,0.05,b).zy.grid(2,1,2,0.5,0,0.5).cxz;
3: top = bcube(0.555,0.05,0.555,b).zy.ty(0.4);
4: table = top + legs;
5: return table;
Example-Script: 'swivel_chair.qmsh'
swivel_chair.qmsh
1: c = cylinder(0.5,1,32)
2: - cylinder(0.45,1,32)
3: - cylinder(0.8,1,32).rz(90).t(0,0.5,0.5)
4: + sphere.s(0.9,0.25,0.9).ty(-0.3)
5: + cylinder(0.45,0.05,32).ty(-0.5)
6: - cube(0.6,0.05,1).ly(5,0.1)
7: + cylinder(0.1,0.5,32).ty(-0.75)
8: + cylinder(0.2,0.1,32).ty(-1)
9: + capsule(0.05,0.5,16,8).rx(90).zz
10: .rx(-10).tz(0.1).ty(-1).ry(36).ringy(5);
11: return c.cy;
Example-Script: 'simple_block_sofa.qmsh'
simple_block_sofa.qmsh
1: b = 0.025;
2: c = bcube(0.25,0.5,0.75,b).lx(2,1.75+0.25).cx.zy
3: + bcube(1.75,0.75,0.25,b).zy.ty(-0.075).rx(-10).t(0,0.25,0.25)
4: + bcube(1.75,0.25,0.75,b).zy;
5: return c;
Example-Script: 'media_stand.qmsh'
Example-Script: 'floor_standing_speaker.qmsh'
floor_standing_speaker.qmsh
floor_standing_speaker.qmsh 1: c = cube(0.2,1,0.2).zy;
2: b = cube(0.18,0.98,0.02).t(0,0.5,-0.1);
3: o = sphere(32,4).rx(90).s(0.15,0.15,0.02).ly(5,0.19).cy.t(0,0.5,0.1);
4: t = torus(0.075,0.005,32,8).rx(90).ly(5,0.19).cy.t(0,0.5,0.1);
5: n = sphere.s(0.05,0.01,0.05).rx(90).ly(5,0.19).cy.t(0,0.5,0.09);
6: ret = c - o - b + t + n;
7: return ret.cy;
Example-Script: 'mini_sub_woofer.qmsh'
mini_sub_woofer.qmsh
1: c = cube(0.15,0.3,0.4);
2: d = cylinder(0.125,0.01,32)
3: + sphere.s(0.25,0.01,0.25).ty(-0.005);
4: d.rz(90).tx(0.075);
5: e = sphere.s(0.1).t(0,-0.075,0.2);
6: f = torus(0.05,0.005,32,16).rx(90).t(0,-0.075,0.2);
7: g = cube(0.13,0.28,0.02).tz(-0.2);
8: return c - e + d + f - g;
Example-Script: 'usb_pen_drive.qmsh'
usb_pen_drive.qmsh
1: c = cube(0.06,0.01,0.025)
2: - cube(0.01,0.01,0.01).t(-0.025,0,0.0075)
3: - cube(0.01,0.01,0.01).t(0.025,0,-0.0075)
4: + cylinder(0.01,0.01,32).t(-0.02,0,0.0025)
5: + cylinder(0.01,0.01,32).t(0.02,0,-0.0025)
6: & capsule(0.01125,1,32,1).rz(90)
7: - cube(0.03,0.008,0.005).tz(0.0125);
8: h = capsule(0.00375,0.02,32,16).rz(90).s(0.5,1,0.5).tz(0.01);
9: h.tx(0.0075).rgb(0.75,0.25,0.25);
10: e = cylinder(0.001,1,4).rz(90).tz(-0.012).lz(2,0.024)
11: + cylinder(0.00025,1,4).rx(90).tx(-0.03).lx(2,0.06);
12: t = torus(0.01,0.00025,32,4)
13: & cube.zx.nzz;
14: t.t(0.02,0,-0.0025);
15: t = t + t.duo.ry(180);
16: u = cube(0.0025,0.005,0.012).tx(0.03);
17: p = cube(0.02,0.004,0.011).tx(0.03)
18: - cube(0.02,0.0035,0.0105).tx(0.03)
19: + cube(0.019,0.00125,0.0105).t(0.03,-0.00125,0).rgb(0.25,0.5,0.75)
20: - cube(0.002,0.005,0.002).lz(2,0.005).cz.t(0.035,0.0025,0)
21: + cube(0.0175,0.00025,0.00125).t(0.03,-0.000675,0)
22: .rgb(1,0.75,0.5).lz(4,0.0025).cz;
23: c.rgb(0.25);
24: e.rgb(0.5);
25: t.rgb(0.5);
26: u.rgb(0.375);
27: ret = c - e - t - u + h + p;
28: return ret;
Example-Script: 'cylindrical_light_shade.qmsh'
cylindrical_light_shade.qmsh
cylindrical_light_shade.qmsh 1: c = torus(0.2,0.0025,64,8).ly(2,0.25).cy;
2: t = cylinder(0.0025,0.16,8).rx(90).zz.tz(0.04).ringy(3)
3: + cylinder(0.04,0.005,64)
4: - cylinder(0.02,0.005,64);
5: t.ty(0.1275);
6: s = cylinder(0.201,0.25,64)
7: - cylinder(0.199,0.25,64);
8: s.rgba(0,0.5,1,0.5);
9: // s.rgba(1,0.25,0.25,0.5);
10: return c + t + s;
Example-Script: 'low_watt_light_bulb.qmsh'
low_watt_light_bulb.qmsh
1: c = cylinder(0.025,0.02,32)
2: - torus(0.025,0.001,32,4).ty(-0.01)
3: - torus(0.025,0.0005,32,4).ty(-0.005)
4: + sphere(32,16).s(0.05,0.025,0.05).ty(0.01)
5: + cylicone(0.015,0.01,0.01,32).ty(0.0225)
6: - torus(0.015,0.005,32,32).ty(0.02575)
7: + cylicone(0.01,0.0075,0.02,32).ty(0.0275)
8: + capsule(0.001,0.02,8,4).rx(90).ty(0.035)
9: - torus(0.0075,0.001,32,8).ty(0.0375)
10: + sphere(16,8).s(0.008,0.001,0.004)
11: .ty(0.0375).lz(2,0.006).cz;
12: h = cylinder(0.005,0.01,32)
13: + torus(0.005,0.0005,32,4).ty(-0.005);
14: hs = h.duo.nzy.lx(2,0.0125).cx.tz(0.0125);
15: hs = hs.ringy(3);
16: p = cylinder(0.004,0.07,32);
17: ps = p.duo.nzy.lx(2,0.0125).cx.tz(0.0125);
18: ps = ps.ringy(3);
19: r = torus(0.00625,0.004,32,32).rx(90)
20: & cube.nzy;
21: rs = r.duo.t(0,-0.07,0.0125).ringy(3);
22: ret = c - hs + ps + rs;
23: return ret.cy;
Example-Script: 'rotary_dial.qmsh'
rotary_dial.qmsh
1: s = sphere(64,32).sy(0.5)
2: - cube(0.02,0.1,0.02).tz(0.5).rx(20).sy(0.5).ringy(16).rgb(0.25)
3: - sphere(8,2).s(0.025,0.1,0.025).tz(0.5).rx(45).sy(0.5).rgb(0.25);
4: b = cube(5,5,5).nzy;
5: h = s.duo.rx(180).zy.ty(0.0125);
6: k = s & sphere(64,32).s(0.25,1,0.875);
7: return s - h + k - b;
Example-Script: 'championship_ring.qmsh'
championship_ring.qmsh
1: a = cylinder(0.5,1,64).rx(90)
2: + cube(1,2,1).zy;
3: c = cylinder(0.5,1,64)
4: & a
5: - cylinder(0.475,1,64).rx(90)
6: - cube.nzy.zz.tz(0.155)
7: - cube.nzy.nzz.tz(-0.155);
8: t = cube.zy
9: & sphere(64,32).s(0.95).sy(0.25);
10: t.ty(0.5).rgb(0.25);
11: c.rgb(1,0.8,0.5);
12: return c + t;
For further examples refer to the accompanying PDF collection: 2
8 QMSH Scripts.
→
28 QMSH Scriptsa collection of 256 free-to-use example qmsh scripts written by the language's author in order to help elucidate the subtleties of the grammar.
→ 28 QMSH Scripts--
To keep up to date with the latest developments in the suite of examples - refer to the supplementary mobile collection: QMSH Scripts by Codemine.
Note: ensure you have read and understood the Terms-of-Use before downloading.
Terms-of-Use
The terms and conditions that govern the use of the Quick-Mesh Kernel, Scripting-Language and the associated tools and resources are summarised below.
→
Quick-Mesh is provided AS IS - WITHOUT ANY WARRANTY. →
Quick-Mesh is Free-to-Use for Non-Commercial and Not-for-Profit Endeavours. →
Quick-Mesh may also be used within Commercial-Contexts subject to Registration as an Industrial-User through Codemine-Industrial-Software. →
Quick-Mesh is NOT Open-Source-Software - it is Closed-Source Software. →
Quick-Mesh may NOT be used in Safety-Critical-Contexts. →
Quick-Mesh may NOT be used to Facilitate Criminal or Terrorist Activity.
The terms and conditions related to the rights to appropriate intellectual property largely conform to the view that 'one-has-rights-to-the-things-one-creates'.
In terms of Codemine's rights to QMSH:
→
Quick-Mesh's Kernels', Editors' and Plugins' Physical Implementations Remain the Exclusive Property of K. Edum-Fotwe and Codemine-Industrial-Software. →
Unauthorised Redistribution or Resale of Quick-Mesh is Strictly Prohibited and May Incur Liability to Criminal Prosecution and/or Civil Claims for Damages. →
Codemine-Industrial-Software Retain All Intellectual Property Rights Pertaining to the Implementation of the Quick-Mesh Kernel, Editors, Plugins and Tool-Chain. →
Codemine-Industrial-Software Retain All Intellectual Property Rights Pertaining to the Formal Definition of the Quick-Mesh Scripting-Language. →
Codemine-Industrial-Software Retain All Intellectual Property Rights Pertaining to the Production, Maintenance and Distribution of Quick-Mesh's Documentation.
In terms of an end-user's rights to content (scripts and models):
→
End-Users Retain All Intellectual Property Rights Pertaining to the Novel Content (Scripts and Models) that they Create using Quick-Mesh. →
End-Users Accept Legal and Economic Responsibility for Ensuring their Use of Quick-Mesh Does Not Infringe upon the IP Rights of Third-Parties.
In terms of end-users' responsibilities towards one another:
→
End-Users Agree to be Respectful and Courteous towards other End-Users. →
End-Users Agree to Act Fairly and in a Non-Discriminatory Manner towards other End-Users in Matters Pertaining to the Distribution, Commercialisation or General Monetisation of Content Created using Quick-Mesh.
Privacy Policy
The privacy policy applicable to Quick-Mesh online is simple - and is the same as the privacy policy applicable to all of Codemine's online sites and services.
In order to protect the personal information of users - Codemine does not track, monitor nor record any information enabling the identification of individual users. Codemine's policy is strictly Cookie-Free, Tracker-Free, Ad-Free and Spam-Free.
→
Codemine operates a Cookie-Free policy for all of its online content. Essentially Codemine does not use browser technologies such as cookies. →
Codemine does not engage in the distribution of unsolicited mail for any reason. →
If you choose to contact Codemine by email (for example to report a bug or an issue, or to provide feedback or request a new feature, or for technical support), your message will be handled by Codemine's mail system. Codemine uses ProtonMail as its mail system - therefore emails to Codemine are also subject to the privacy considerations and behavioural constraints stated in Proton's Terms-of-Service. →
Whilst Codemine's direct online offerings are cookie-free, tracker-free, ad-free and spam-free - be aware that accessing content created by Codemine which is available through third-party distribution channels will result in behaviour outside of Codemine's control. As concrete examples of this: the QMSH-Editor's (currently deprecated) Google Play-Store listing and the QMSH-Plugin's Unity Asset-Store listing will result in cookies served by Google and Unity-Technologies, their affiliates and partners.