Shapes

Introduction

A shape represents a region on the plane and are divided in 5 types:

  • EmptyShape, mathematically it’s the empty set with no interior points

  • WholeShape, mathematically it’s the set with all the points in plane

  • SimpleShape, is represented by only one jordan curve,

  • ConnectedShape, is the intersection some SimpleShape

  • DisjointShape, is the union of some ConnectedShape

For any pair of shapes, you can use operators:

  • | - Union (OR)

  • & - Intersection (AND)

  • - - Subtraction

  • ^ - XOR

  • ~ - Inversion

  • in - Contains

Empty and Whole

They are singleton objects which are used to be returned in boolean operations.

For example, there are some sta

from shapepy import EmptyShape, WholeShape

empty = EmptyShape()
whole = WholeShape()

empty | whole is whole  # OR
empty & whole is empty  # AND
empty ^ whole is whole  # XOR
empty - whole is empty  # SUB
whole - empty is whole  # SUB
~empty is whole  # Invert
~whole is empty  # Invert
empty in whole  # Contains
whole not in empty  # Contains

They are returned when, for any shape:

shape | (~shape)  # Whole
shape & (~shape)  # Empty
shape - shape  # Empty
shape ^ shape  # Empty
shape ^ (~shape)  # Whole

Simple Shape

This shape is described by only one JordanCurve.

  • If the jordan curve is counter-clockwise (positive),
    • The simple shape will be the interior of the curve

  • If the jordan curve is clockwise (negative),
    • The simple shape will be the exterior of the curve

As example, bellow we have a positive (left image) and a negative circle (right image).

pic1 pic2

The easiest way to create it is by using Primitive, which allows creating many simple shapes, like square and circle

from shapepy import Primitive
my_square = Primitive.square()
my_circle = Primitive.circle()

You can also create your custom SimpleShape by using a passing a JordanCurve

from shapepy import JordanCurve, SimpleShape
vertices = [(0, 0), (4, 0), (0, 3)]
jordan = FactoryJordan.polygon(vertices)
simple = SimpleShape(jordan)

It’s possible to operate between two simple shapes:

from shapepy import Primitive
my_square = Primitive.square()
my_circle = Primitive.circle()

~my_square  # INVERT
my_square | my_circle  # OR
my_square & my_circle  # AND
my_square - my_circle  # SUB
my_square ^ my_circle  # XOR
(0, 0) in my_square  # Contains
my_square in my_circle  # Contains

You find bellow a table with the basic operations between two positive circles (simple shapes).

Operations between two positives simple shapes

Connected Shape

This shape is described by the intersection of simple shapes:

\[C = \bigcap_i S_i\]

Two examples of connected shapes are bellow.

pic3 pic4

The easiest way to create them is by operating between shapes. For example:

from shapepy import Primitive

big_circle = Primitive.circle(radius = 2)
small_circle = Primitive.circle(radius = 1)
hollow_circle = big_circle - small_circle

It’s also possible to create directly the ConnectedShape instance, but it may raise ValueError if the input is wrong:

from shapepy import Primitive, ConnectedShape

big_circle = Primitive.circle(radius = 2)
small_circle = Primitive.circle(radius = 1)
hollow_circle = ConnectedShape([big_circle, ~small_circle])

Disjoint Shape

This shape is described by the union of simple and connected shapes:

\[D = \left(\bigcup_j S_j\right) \cup \left(\bigcup_i C_i\right)\]

Some examples of disjoint shapes are

pic5 pic6

The easiest way to create them is by operating shapes. For example, the code bellow creates the respective figure.

from shapepy import Primitive, ConnectedShape

left = Primitive.circle(radius = 1, center = (-1.5, 0))
right = Primitive.circle(radius = 1, center = (1.5, 0))
disjoint = left | right
Example of disjoint shape created by union of two circles

You can also create directly

from shapepy import Primitive, DisjointShape

left = Primitive.circle(radius = 2)
right = Primitive.circle(radius = 1)
hollow_circle = ConnectedShape([big_circle, ~small_circle])

Boolean Operations

The boolean operations can be tricky, bellow you find tables for operations between two shapes. We represent the shapes categories as \(E\) (empty), \(W\) (whole), \(S\) (simple), \(C\) (connected) and \(D\) (disjoint)

Table for possible results of ~B

\(E\)

\(W\)

\(S\)

\(C\)

\(D\)

\(W\)

\(E\)

\(S\)

\(D\)

\(C\), \(D\)

Table for possible results of A | B

\(E\)

\(W\)

\(S\)

\(C\)

\(D\)

\(E\)

\(E\)

\(W\)

\(S\)

\(C\)

\(D\)

\(W\)

\(W\)

\(W\)

\(W\)

\(W\)

\(W\)

\(S\)

\(S\)

\(W\)

\(W\), \(S\), \(C\), \(D\)

\(W\), \(S\), \(C\), \(D\)

\(W\), \(S\), \(C\), \(D\)

\(C\)

\(C\)

\(W\)

\(W\), \(S\), \(C\), \(D\)

\(W\), \(S\), \(C\), \(D\)

\(W\), \(S\), \(C\), \(D\)

\(D\)

\(D\)

\(W\)

\(W\), \(S\), \(C\), \(D\)

\(W\), \(S\), \(C\), \(D\)

\(W\), \(S\), \(C\), \(D\)

Table for possible results of A & B

\(E\)

\(W\)

\(S\)

\(C\)

\(D\)

\(E\)

\(E\)

\(E\)

\(E\)

\(E\)

\(E\)

\(W\)

\(E\)

\(W\)

\(S\)

\(C\)

\(D\)

\(S\)

\(E\)

\(S\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

\(C\)

\(E\)

\(C\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

\(D\)

\(E\)

\(D\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

Table for possible results of A - B

\(E\)

\(W\)

\(S\)

\(C\)

\(D\)

\(E\)

\(E\)

\(E\)

\(E\)

\(E\)

\(E\)

\(W\)

\(W\)

\(E\)

\(S\)

\(D\)

\(C, D\)

\(S\)

\(S\)

\(E\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

\(C\)

\(C\)

\(E\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

\(D\)

\(D\)

\(E\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

\(E\), \(S\), \(C\), \(D\)

Table for possible results of A ^ B

\(E\)

\(W\)

\(S\)

\(C\)

\(D\)

\(E\)

\(E\)

\(W\)

\(S\)

\(C\)

\(D\)

\(W\)

\(W\)

\(E\)

\(S\)

\(D\)

\(C\), \(D\)

\(S\)

\(S\)

\(S\)

any

any

any

\(C\)

\(C\)

\(D\)

any

any

any

\(D\)

\(D\)

\(C\), \(D\)

any

any

any