Flat - Path Permutations

In this notebook the start and end point of a path (Catmull-Rom Spline) are fixed and all possible ways between given points in between start and end are calculated and displayed.

Imports

from flat import document, shape, rgb, rgba
from bezmerizing import Path, Polyline
from IPython.display import SVG, display
import numpy as np
import random
import itertools
from sympy.utilities.iterables import multiset_permutations

Functions

This section defines functions that will be used later.

# Display a flat page here in the notebook
def show(page):
    display(SVG(page.svg()))
       
# Draw a grid of horizontal and vertical lines based on 
# given coordinates
def draw_grid(page, x_coords, y_coords, color=rgb(200, 200, 200)):
    
    # Get minimum and maximum values 
    min_x, max_x = min(x_coords), max(x_coords)
    min_y, max_y = min(y_coords), max(y_coords)
    
    # Draw vertical lines
    for x in list(x_coords):
        line = shape().stroke(color).line(x, min_y, x, max_y)
        page.place(line)

    # Draw horizontal lines
    for y in list(y_coords):
        line = shape().stroke(color).line(min_x, y, max_x, y)
        page.place(line)

# Translate a list of points into a list of coordinates
def indices_to_coordinates(list_of_indices, coordinates):
    c = []
    for index in list_of_indices:
        x = coordinates[0][index[0]]
        y = coordinates[1][index[1]]
        c.append([x, y])
        
    return c

Flat Document

The following code defines the general setup of the document. It has width and height and a margin. The size of the grid is calculated as the size of the document minus the margin on all sides of the document.

# Width and height of the document
width, height = 400, 400

# Margin between border of the document and
# border of the grid
margin = 10

# Size of the grid
grid_width = width - 2*margin
grid_height = height - 2*margin

# Create the document
d = document(width, height, 'pt')

Grid Definition

The grid is defined through the number of points on the x and y axis. In the next step the coordinates for each point are calculated. This is done with the linspace() function from Numpy (np). It distributes the points on a given range, in this case the size of the grid. It also takes the margin into account.

# Number of points per row 
# (number of cells = row -1)
grid_x = 6
grid_y = 6

# Create coordinates
coords_x = np.linspace(margin, margin+grid_width, grid_x)
coords_y = np.linspace(margin, margin+grid_height, grid_y)

print(coords_x)
print(coords_y)
[ 10.  86. 162. 238. 314. 390.]
[ 10.  86. 162. 238. 314. 390.]

Draw a catmull-rom spline on the grid

See the bezmerizing demo for a description of the catmull-rom spline.

# Add a page to the document
page = d.addpage()

# Call the function to draw a grid
# As input it takes the list of coordinates defined above
draw_grid(page, coords_x, coords_y)

# Draw a path betweeen points
# For catmull-rom the first and last points have to be duplicated
# (or replaced by close values)
points = [[0, 2], [0, 2], [1, 1], [2, 4], [3, 2], [4, 2], [5, 3], [5, 3]]
# Translate the points into coordinates
coords = indices_to_coordinates(points, [coords_x, coords_y])
# Feed the coordinates into the Polyline object
pline = Polyline(coords)

# Transform the Polyline from above into a spline
spline = pline.catmull_spline(tightness=0.1)
# Transform it into a path
path = spline.to_path()

# Feed the path into flat's path function
fig = shape().stroke(rgb(0, 0, 0)).nofill().width(1)
page.place(fig.path(path))

# Feed the page into the show() function to display it inside the notebook
show(page)
_images/flat_06_permutations_10_0.svg

Calculate permutations

The start and end point will be fixed and the order of the points in-between will be permutated.

points = [[0, 2], [0, 2], [1, 1], [2, 4], [3, 2], [4, 2], [5, 3], [5, 3]]
print('points:', points)

# Reduce the list to the mid-points
variable_points = points[2:-2]
print('variable_points:', variable_points)
points: [[0, 2], [0, 2], [1, 1], [2, 4], [3, 2], [4, 2], [5, 3], [5, 3]]
variable_points: [[1, 1], [2, 4], [3, 2], [4, 2]]
permutations = list(multiset_permutations(variable_points))
for p in permutations:
    print(p)
print(len(permutations), 'permutations')
[[1, 1], [2, 4], [3, 2], [4, 2]]
[[1, 1], [2, 4], [4, 2], [3, 2]]
[[1, 1], [3, 2], [2, 4], [4, 2]]
[[1, 1], [3, 2], [4, 2], [2, 4]]
[[1, 1], [4, 2], [2, 4], [3, 2]]
[[1, 1], [4, 2], [3, 2], [2, 4]]
[[2, 4], [1, 1], [3, 2], [4, 2]]
[[2, 4], [1, 1], [4, 2], [3, 2]]
[[2, 4], [3, 2], [1, 1], [4, 2]]
[[2, 4], [3, 2], [4, 2], [1, 1]]
[[2, 4], [4, 2], [1, 1], [3, 2]]
[[2, 4], [4, 2], [3, 2], [1, 1]]
[[3, 2], [1, 1], [2, 4], [4, 2]]
[[3, 2], [1, 1], [4, 2], [2, 4]]
[[3, 2], [2, 4], [1, 1], [4, 2]]
[[3, 2], [2, 4], [4, 2], [1, 1]]
[[3, 2], [4, 2], [1, 1], [2, 4]]
[[3, 2], [4, 2], [2, 4], [1, 1]]
[[4, 2], [1, 1], [2, 4], [3, 2]]
[[4, 2], [1, 1], [3, 2], [2, 4]]
[[4, 2], [2, 4], [1, 1], [3, 2]]
[[4, 2], [2, 4], [3, 2], [1, 1]]
[[4, 2], [3, 2], [1, 1], [2, 4]]
[[4, 2], [3, 2], [2, 4], [1, 1]]
24 permutations
# Add start and end points

permutations = [points[:2] + perm + points[-2:] for perm in permutations]

for p in permutations:
    print(p)
[[0, 2], [0, 2], [1, 1], [2, 4], [3, 2], [4, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [1, 1], [2, 4], [4, 2], [3, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [1, 1], [3, 2], [2, 4], [4, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [1, 1], [3, 2], [4, 2], [2, 4], [5, 3], [5, 3]]
[[0, 2], [0, 2], [1, 1], [4, 2], [2, 4], [3, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [1, 1], [4, 2], [3, 2], [2, 4], [5, 3], [5, 3]]
[[0, 2], [0, 2], [2, 4], [1, 1], [3, 2], [4, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [2, 4], [1, 1], [4, 2], [3, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [2, 4], [3, 2], [1, 1], [4, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [2, 4], [3, 2], [4, 2], [1, 1], [5, 3], [5, 3]]
[[0, 2], [0, 2], [2, 4], [4, 2], [1, 1], [3, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [2, 4], [4, 2], [3, 2], [1, 1], [5, 3], [5, 3]]
[[0, 2], [0, 2], [3, 2], [1, 1], [2, 4], [4, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [3, 2], [1, 1], [4, 2], [2, 4], [5, 3], [5, 3]]
[[0, 2], [0, 2], [3, 2], [2, 4], [1, 1], [4, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [3, 2], [2, 4], [4, 2], [1, 1], [5, 3], [5, 3]]
[[0, 2], [0, 2], [3, 2], [4, 2], [1, 1], [2, 4], [5, 3], [5, 3]]
[[0, 2], [0, 2], [3, 2], [4, 2], [2, 4], [1, 1], [5, 3], [5, 3]]
[[0, 2], [0, 2], [4, 2], [1, 1], [2, 4], [3, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [4, 2], [1, 1], [3, 2], [2, 4], [5, 3], [5, 3]]
[[0, 2], [0, 2], [4, 2], [2, 4], [1, 1], [3, 2], [5, 3], [5, 3]]
[[0, 2], [0, 2], [4, 2], [2, 4], [3, 2], [1, 1], [5, 3], [5, 3]]
[[0, 2], [0, 2], [4, 2], [3, 2], [1, 1], [2, 4], [5, 3], [5, 3]]
[[0, 2], [0, 2], [4, 2], [3, 2], [2, 4], [1, 1], [5, 3], [5, 3]]

Loop over permutations

for p in permutations:


    # Add a page to the document
    page = d.addpage()

    # Call the function to draw a grid
    # As input it takes the list of coordinates defined above
    draw_grid(page, coords_x, coords_y)

    # Draw a path betweeen points
    # For catmull-rom the first and last points have to be duplicated
    # (or replaced by close values)
    points = p
    # Translate the points into coordinates
    coords = indices_to_coordinates(points, [coords_x, coords_y])
    # Feed the coordinates into the Polyline object
    pline = Polyline(coords)

    # Transform the Polyline from above into a spline
    spline = pline.catmull_spline(tightness=0.1)
    # Transform it into a path
    path = spline.to_path()

    # Feed the path into flat's path function
    fig = shape().stroke(rgb(0, 0, 0)).nofill().width(1)
    page.place(fig.path(path))

    # Feed the page into the show() function to display it inside the notebook
    show(page)
_images/flat_06_permutations_16_0.svg_images/flat_06_permutations_16_1.svg_images/flat_06_permutations_16_2.svg_images/flat_06_permutations_16_3.svg_images/flat_06_permutations_16_4.svg_images/flat_06_permutations_16_5.svg_images/flat_06_permutations_16_6.svg_images/flat_06_permutations_16_7.svg_images/flat_06_permutations_16_8.svg_images/flat_06_permutations_16_9.svg_images/flat_06_permutations_16_10.svg_images/flat_06_permutations_16_11.svg_images/flat_06_permutations_16_12.svg_images/flat_06_permutations_16_13.svg_images/flat_06_permutations_16_14.svg_images/flat_06_permutations_16_15.svg_images/flat_06_permutations_16_16.svg_images/flat_06_permutations_16_17.svg_images/flat_06_permutations_16_18.svg_images/flat_06_permutations_16_19.svg_images/flat_06_permutations_16_20.svg_images/flat_06_permutations_16_21.svg_images/flat_06_permutations_16_22.svg_images/flat_06_permutations_16_23.svg