All posts by mike.vasiljevs

Park Generator 0.4.0, Rays Rule

Rays rule park in a fitted region

New Rules

  • Rays rule – ‘ray’-like partitioning of the input region
    • Entrance positions need to be given as a list parameter, which informs where on the boundary the entrances should be placed.


  • New match condition, border – boundary-touching regions are selected.

Technical Details

  • Tested using Shape Fitting plugin – a Quad is provided in conjunction with the original Input Region; this, however, it is still under development
  • shape_num_segments” attribute determines circle shape resolution
  • Layout library (DLL) no longer throws exceptions but logs errors instead.

Edge Placement Selection

NOTE currently scatter and place rules use different discreet selectors.

Most basic discrete selection is just a list of parameter values on the range [0, 1]:

[pos1, pos2, ... posn]

One can also specify the interval between the items:


It is possible to specify start offset

[offset_start : item_offset]

Or end offset:

[item_offset : offset_start]

Or  both:

[offset_start : item_offset : offset_end]
  • offset_start, offset_end (double), the distance between the start of the edge and the first item, or respectively end of the edge and the last item. double values
  • item_offset – either:
    • ninterval_count (int) – number of intervals between items; e.g. to place n items interval count is n-1
    • linterval_length (double) – desired interval length, could be less or more, depending on how many items fit in the area.

Shape Fitting 0.2.0

Shape Fitting is a simple SketchUp plugin that finds a simpler shape with fewer vertices from an input shape with many vertices. Plugin originates from one functionality of Park Generator, which was employed when the initial input region had to be mapped to a quad somehow before Grid rule can be applied to it. The quad area should match the area of the input polygon in the best possible way, and that does not necessarily mean minimal differences in areas . Rather, the quad should act as a template for the Grid rule – we should bear in mind that the ultimate goal is for the resulting park to look good. Park content is bounded (practically speaking – clipped) by the input region.

The plugin is available at the Extensions Warehouse store. Widgets are created with the SKUI library.

Currently, the plugin uses three methods to find this quad, and these are grouped into two classes below.

Bounding Boxes Methods

AABB (Axis Aligned Bounding Box) and OBB (Oriented Bounding Box)  enclose the entire input polygon. While AABB aligned to x and y (world) coordinate axes, as the name suggests, OBB is rotated – to find the rectangle with the minimal area that contains the entire input polygon. The plugin uses GTE library to compute OBB, which implements rotating callipers algorithm [1].

Axes Corners method uses x- and y-axes as the name suggests. If OBB is chosen from the Box type parameter – axes are mapped to the local coordinates of the oriented box. Algorithm works as follows: from the centre of the polygon rays are cast to the corners of the box (‘corners of axes’) and resulting edge intersections make up the quad vertices. It is worth noting that the fitted polygon (quad) vertices lay on the boundary of the input, which (for the most time) do not coincide with those of the input polygon.

Angle Thresholding Methods

A Naive angle thresholding method filters input vertices by an angle threshold between adjacent edges. For instance, if the dot product of the adjacent edges is less than a certain value (e.g. 0.5) then the vertex angle is sharp enough for this vertex to be classified as a corner. However, depending on the input shape, for a  given threshold value  there could be an arbitrary number of corners detected! Next method, an improvement of this one, fixes this.

Adaptive thresholding method tries to search for the optimal threshold that delivers specified number of corners (4 in a case of a quad). The algorithms takes the initial cosine range of [-1, 1],  picks a threshold somewhere in the middle, and, until the threshold produces the correct number of corners – iteratively searches in one of the subranges – either below (to get fewer corners) or above (to get more corners) the threshold. Currently, for “somewhere in the middle” the plugin picks a value exactly in the middle (e.g. 0.5 for [0, 1] range), although other picks could possibly be tried too to make convergence faster! This algorithm, however, does not terminate for every case, such as when all angles are equal (a poly-circle). To solve this, the total number of iterations is limited, and if no threshold found algorithms returns an empty polygon.

Rays Rule

Partitions input region using straight path segments in the manner of ‘rays‘. Intersections of ‘ray’ segments with each other are called junctions, and intersections at iregion boundary – entrancesDelaunay Triangulation is used (related to Voronoi Diagram, which is its dual).

Entrances (boundary intersections) are determined by the list of boundary parameters or selections. Junction placement (ray intersections) is determined by sample distribution radius:

rays(boundary_selections, radius) 
 { RegionList } { PathList } { JunctionList }

Alternatively, a number of samples can be specified, and the algorithm tries to guess the sample radius:

rays(boundary_selections, number_of_samples) 
 { RegionList } { PathList } { JunctionList }

Optionally, minimal offset from junctions to the boundary can be provided:

rays(boundary_selections, ..., junction_offset) 
 { RegionList } { PathList } { JunctionList }
  • boundary selections – list of parameter values within the range [0..1]. For example [0, 0.25, 0.5, 0.75] will place entrances at the corners of a square.
  • radius, number_of_samples – minimum radius between any two junctions, and respectively the number of junctions. Also, see Cells Rule for the explanation with one difference: in Cells Rule radius refers to the distance between quarters, rather than junctions ).
  • offset – centres of the junctions is placed with this minimum distance from the boundary.
  • RegionList, PathList, JunctionList – label selector lists (see Grid Rule for explanation).

Select Rule

Re-write incoming geometry to a different set of labels.

select { RegionList }

RegionList – label selector list, list of selector expressions applied on the input shape.

No geometry is modified, only labels are assigned and attributes set. The purpose of this rule is to remove redundancy of repeating the same operations on one label in different selector blocks, for instance:

InputLabel --> place(CENTRE) 
 { 50%: Border1 | else: Border2  } 
 { i("circle", 10) Inserted } 
 { 50%: Border1 | else: Border2  }

can be rewritten as:

InputLabel --> place(CENTRE) 
{ Border } { i("circle", 10) Inserted } { Border } 

Border --> select { 50%: Border1 | else: Border2 }

Rule application makes even more sense when selector expression lists are longer, or when the same label is assigned in a number of different rules.

Cells Rule

Partitions input region into more natural looking “cell-like” quarters that resemble biological cells. Voronoi Diagram partitioning method is used.

Sample radius determines centre of a cell:

{ RegionList } { PathList } { JunctionList }

Alternatively number of samples can be requested and radius best matching radius will be guessed (this is currently a not very accurate procedure):

 { RegionList } { PathList } { JunctionList }

With an optional smoothing parameter:

cells(..., M(smoothing_factor))
 { RegionList } { PathList } { JunctionList }

Symmetry parameter is added at the end and is also optional:

cells(..., S(symmetry_id))
 { RegionList } { PathList } { JunctionList }
  • radius – minimum distance between any two path junctions; larger radius means fewer junctions. Alternatively number_of_samples can be used:
  • number_of_samples – specify actual number of junctions to place within the region. Algorithm tries to take a guess the appropriate radius, however the actual radius than the ideal one for the appropriate number of samples.
  • smoothing_factor – how much should the cells be smoothed by. Smoothing reduces a cell size.
  • symmetry_id
    • 0: no symmetry
    • 1: x symmetry
    • 2: y symmetry
    • 3: x and y symmetry (which is also a boolean AND of 1 and 2)
  • RegionList, PathList, JunctionList – label selector lists, as in Grid Rule.

Park Generator 0.3.0, Cells Rule

 New Rules

  • Cells rule – natural looking region partitioning (pictures above)
    • smoothing
    • X and Y junction symmetry
  • Select rule – rewrite labels without modifying input geometry.


  • 01indexing modulation
    • when attribute “selection_internal_minimal” is set (not equal to 0) – no boundary-touching edges are included in inner selection
  • insert operator
    • the second parameter changed to weight (from the number of passes – see below); can be a random range value; 0.5 by default
  •  Smoothing
    • Adaptive smoothing: keep smoothing until the largest edge is less or equal to the threshold attribute “smoothing_len_threshold_max” (default: 10%)
    • Number of passes bounded by attributes:
      • smoothing_num_passes_min” (default: 1) – number of passes that is applied always
      • smoothing_num_passes_max” (default: 8) – upper limit in adaptive smoothing, stop at this number of passes regardless.

Technical Details

  • a default value for the second parameter in insert operator is set at run time instead of compile time (parsing).

Park Generator 0.2.0, Stochastic Selectors

General Changes

  • Stochastic selectors
  • Place rule – single CENTRE parameter placed shape in the middle of the region
  • Attributes
    • could be set using values of other attributes
      • for instance set(a, 20) set(b, a)
    • new attribute “elevation” specifies the amount to extrude upwards (push/pull)
    • new type attribute “border” – sets stone-like material to the region and elevates 6 units up
  • Scatter rule – samples that are placed along the edge (EDGE_SELECTION) are jittered by a small amount to make them look more natural.

Grammar Changes

  • place rule – third selector block is optional (will use the first for the second shape).

Technical Details

  • Attribute system is re-written. Global attribute evaluation is performed after the entire Rulefile is parsed (thus the order of assignment is not important). Shape attributes are evaluated during rule application
  • Grid rule fixes: path widths for non-rectangular input regions are evenly adjusted.

Park Generator 0.1.0


General Changes

  • Insert rule as a standalone rule
  • Two new park examples
    • demonstration of Place, Peel and Insert rule use
    • fountain component added
  • Two new region type attributes:
    • bushes” – set to get bush-like park region
    • loam” – for placement of trees and flowerbeds; default type for inserted regions.

Grammar Changes

  • set operator – insert/update attribute
  • insert operator – insert geometry.

Technical Details

  • Shape attributes, attribute propagation
  • Insert rule clipping fixed
  • Insert rule 01indexing fixes
  • Scatter rule EDGE_SELECTION modifier
  • Negative ranges allowed in extractStringByRange().

Boundary Range Selection

Boundary Range Selection List

Selection1 Selection2 ... SelectionN

Selectioni – Selection Entry, can be one of the following:

  • Ranged Selection
  • Special Selection
  • Named Selection

Ranged Selection

Range selection is the most basic type of (range) selection that simply specifies subset of boundary range parametrised on the range [0..num_edges]:

[lower, upper]

lower, upper – values within without boundary range; lower must be less than upper. Value can be specified as a doublepercent, Random Range or named attribute.

Special Selection

upper and lower as described above.

Numbered selection is the synonym to Range Selection (see above):

num[lower, upper]

Edge Angle Selection:

ea[lower, upper]

Angle Range Selection:

ar[lower, upper]

Cardinal Directions Selection:

dir[lower, upper]
  • dir – cardinal direction label,  either “N“, “E“, “S” or “W“.
  • upper, lower are within the range [0..1]