Batch Objects
Batch objects along with the Shape objects are the main building blocks of SİMETRİ. They are used to group multiple shapes, paths, and other Batch objects together, allowing for complex designs to be created easily. A Batch object can contain other Batch objects, enabling a hierarchical structure for organizing shapes and patterns.
As the name suggests, Batch objects can be used to modify its elements all at once. For example, you can change the color of all shapes in a Batch object with a single command. For example; batch.set_attribs('fill_color', sg.red) will change the fill color of all shapes in the Batch object to red.
Batch objects have no style properties. They are used to group shapes and other Batch objects together. The Batch object itself does not have any visual identity itself, but it can be used to apply transformations and styles to the shapes it contains.
Batch objects have bounding-boxes, which are used to define the area that the Batch object occupies. The bounding-box of a Batch object is the smallest rectangle that can enclose all the shapes and other Batch objects it contains. The bounding-box can be used as reference points/lines to apply transformations to the Batch object as a whole.
Batch objects behave like Python lists and sets. See the List Operations and Set Operations sections for more details. These operations make Batch objects very flexible and powerful for creating complex designs while keeping the data structure simple and easy to use. Most objects in SİMETRİ and its extensions inherit from Shape and Batch classes.
The Structure of Batch objects.
Batch objects can contain other Batch objects.
Creating a Batch Object
Batch objects can be created using the Batch class. They can be initialized with no arguments, with a single item, or a list of items. The items can be any object, including other Batch objects. The following example shows how to create a Batch object with a variety of items:
import simetri.graphics as sg
shape1 = sg.Shape()
shape2 = sg.Shape()
shape3 = sg.Shape()
batch1 = sg.Batch()
batch2 = sg.Batch(shape1)
batch3 = sg.Batch([batch2, shape2, shape3])
Implicitly Creating a Batch Object
When we transform a Shape object with repetitions, a Batch object is implicitly created. For example, when we use the Shape.rotate method with repetitions, a Batch object is created to hold the rotated shapes. The following example shows how this works:
>>> import simetri.graphics as sg
>>> shape = sg.Shape([(0, 0), (100, 100)])
>>> shapes = shape.rotate(sg.pi/6, reps=5)
>>> shapes.type
<Types.BATCH: 'BATCH'>
>>> len(shapes)
6
>>>
When we transform a Batch object with multiple repetitions, this operation does not yield a new Batch object. Instead, the original Batch object is modified in place (the transformed objects are appended to the Batch). The following example shows how this works:
>>> import simetri.graphics as sg
>>> shape = sg.Shape([(0, 0), (100, 100)])
>>> batch = sg.Batch(shape)
>>> batch.translate(100, 0, reps=3)
Batch(Shape(((0.0, 0.0), (100.0, 100.0)))...Shape(((300.0, 0.0), (400.0, 100.0))))
>>> len(batch)
4
>>>
Transformations with zero repetitions modify the original Shape/Batch object without generating new items.
This allow us to apply consecutive transformations via method chaining to the same Batch object without having to handle the intermediate results. For example, we can rotate and translate a Batch object in a single command:
>>> import simetri.graphics as sg
>>> shape = sg.Shape([(0, 0), (100, 100)])
>>> batch = sg.Batch(shape)
>>> batch.rotate(sg.pi/6, reps=5).translate(100, 0, reps=3)
Batch(Shape(((0.0, 0.0), (100.0, 100.0)))...Shape(((300.0, 0.0), (163.3974596215561, -36.60254037844381))))
>>> len(batch)
24
>>>
In SİMETRİ, some operations (transformations, canvas.draw, etc.) can be chained together.
Batch Object Properties
Batch objects have the following properties:
- id
- The id of the
Batchobject. This is a unique identifier (positive integer) for theBatchobject, created during its construction. - active
- The active state of the
Batchobject. This is a boolean value that indicates whether theBatchobject is active or not. If theBatchobject is active and visible, it will be displayed on the canvas when drawn.When a
Batchobject is not active, it cannot be transformed. - visible
- The visibility state of the
Batchobject. This is a boolean value that indicates whether theBatchobject is visible or not. If theBatchobject is not visible, it will not be displayed on the canvas when drawn. - all_elements
- Return a list of all elements in the batch, including the elements in the nested batches.
- all_shapes
- Return a list of all shapes in the batch, including the shapes in the nested batches.
- all_vertices
- Return a list of aggregated list of all vertices from all
Shapeobjects in the batch, including the shapes in the nested batches. - all_segments
- Return a list of all segments in the batch, including the segments in the nested batches.
- ids
- Return a list of all unique ids of the items in the batch. If the element does not have an
idattribute thenid(item)will be used. - all_ids
- Return a list of all unique ids of the items in the batch, including the items in the nested batches. If the element does not have an
idattribute thenid(item)will be used. This is similar toidsbut it returns a list of all ids, including duplicates.
List Operations
Batch objects are similar to Python lists. They can be used as lists and have similar methods. The main difference is that Batch objects can only contain unique items. If you try to add an item that already exists in the Batch, it will raise a warning message. The following methods are available for Batch objects:
- append(item)
- Add an item to the end of the items. It will fail (will trigger a warning message, it doesn't raise an error) if this would cause redundant items in the Batch object. The item can be any object.
- clear()
- Remove all items from the
Batch. - copy()
- Return a copy of the
Batchobject. Not just the items but the wholeBatchobject will be copied. - count(item)
- Since all items are unique, count will return either 1 or 0. It doesn't check for equivalence of the items, it checks for identical objects. It will return 1 if there is an item with the same
id. - extend(
) - Add items from another sequence of items to the end of the items. It will raise a warning if this would cause redundant items in the
Batchobject. Identical items will be ignored. - index(item, start=0, end=None)
- Return the index of the first occurrence of a specified item. It will raise a
ValueErrorif the item is not found. Thestartandendarguments are optional and can be used to specify a range in which to search for the item. - insert(index, item)
- Insert an item at a specified position. It will fail if this would cause redundant items in the
Batchobject. - pop(ind=-1)
- Remove and return the item at the specified position (or the last item if no index is specified).
- remove(item)
- Remove the first occurrence of a specified item. It will raise a
ValueErrorif the item is not found. - reverse()
- Reverse the order of the items.
- sort(key, reverse=False)
- Sort the items in ascending order (by default) or in descending order by setting the
reverseargument to be True.keyis a function that takes an (item) as an argument and returns a value that will be used for sorting. Unlike Python's sort method the key argument is not optional.
Indexing and Slicing
Batch objects support indexing and slicing. You can access individual items or a range of items using Python's indexing and slicing syntax:
>>> import simetri.graphics as sg
>>> batch = sg.Batch()
>>> batch.append(sg.Shape([(0, 0), (100, 100)]))
>>> batch.append(sg.Shape([(100, 100), (200, 200)]))
>>> batch.append(sg.Shape([(200, 200), (300, 300)]))
>>> batch[0] # Access the first item
Shape(((0.0, 0.0), (100.0, 100.0)))
>>> batch[1:] # Access the second and third item
Shape(((100.0, 100.0), (200.0, 200.0))), Shape(((200.0, 200.0), (300.0, 300.0)))
>>>
Set Operations
Batch objects can be used as sets (batch.ids is used for hashing).
Items are compared using their id attributes. If the item does not have an id attribute then id(item) will be used. This means that two items with the same content but different ids will be considered as distinct items.
The following methods are available for Batch objects:
- union(other: Batch)
- Return a new
Batchobject that contains all the items from bothBatchobjects. If there are any duplicate items, they will be removed. - intersection(other: Batch)
- Return a new
Batchobject that contains the items that are present in bothBatchobjects. - difference(other: Batch)
- Return a new
Batchobject that contains the items that are present in the firstBatchobject but not in the secondBatchobject. - symmetric_difference(other: Batch)
- Return a new
Batchobject that contains the items that are present in eitherBatchobject but not in both. - issubset(other: Batch)
- Return True if the first
Batchobject is a subset of the secondBatchobject, otherwise return False. - issuperset(other: Batch)
- Return True if the first
Batchobject is a superset of the secondBatchobject, otherwise return False. - isdisjoint(other: Batch)
- Return True if the two
Batchobjects have no items in common, otherwise return False.
Batch Objects' Additional Methods
In addition to the methods mentioned above, Batch objects have the following additional methods:
- merge_shapes() -> Batch
- Merge all shapes in the batch into a single shape where possible. This is useful for creating complex shapes from simpler ones. This does not modify the batch object or the shapes in it. It returns a new
Batchobject that contains the merged shapes. - set_attribs(attrib: str, value: Any, key: callable=None) -> Self
-
Set the specified attribute for all applicable items in the batch. The attribute can be any attribute of the items in the batch, if an item doesn't have the given attribute then it will be ignored. This is useful for applying a common attribute to all items in the batch.
If the optional
keyargument is provided, it should be a callable that takes an item as an argument and returns a boolean value. The attribute will only be set for items that return True when passed to thekeyfunction.For example, if you want to set the fill color of all shapes in the batch with more than 4 vertices, you can use the following code:
This will set the fill color of all shapes in the batch with more than 4 vertices to red.
Batches as Iterators
Batch objects can be used as iterators. This means that you can use them in a for loop or any other context that requires an iterable object. The following example shows how to use a Batch object as an iterator:
>>> import simetri.graphics as sg
>>> batch = sg.Batch()
>>> batch.append(sg.Shape([(0, 0), (100, 100)]))
>>> batch.append(sg.Shape([(100, 100), (200, 200)]))
>>> batch.append(sg.Shape([(200, 200), (300, 300)]))
>>> for item in batch:
... print(item)
...
...Shape(((0.0, 0.0), (100.0, 100.0)))
...Shape(((100.0, 100.0), (200.0, 200.0)))
...Shape(((200.0, 200.0), (300.0, 300.0)))
>>> for item in batch:
... item.fill_color = sg.red
... item.line_color = sg.blue
>>>
Bounding Box of a Batch Object
Batch objects have bounding-boxes, which are used to define the area that the Batch object occupies. The bounding-box of a Batch object is the smallest rectangle that can enclose all the shapes and other Batch objects it contains. The bounding-box can be used as reference points/lines to apply transformations to the Batch object as a whole. For more information about bounding-boxes, see the Bounding Box section.
