fabriks 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
fabriks/__init__.py ADDED
@@ -0,0 +1,244 @@
1
+ """fabriks: a level-of-detail mesh wire format.
2
+
3
+ A mesh collection is an **octree of surfaces** written as one self-describing tree, so a
4
+ renderer can fetch the detail it needs for the view it has instead of the whole thing::
5
+
6
+ <prefix>/
7
+ fabriks.json <- the manifest, written LAST
8
+ catalog/cells.parquet <- the spatial index, one row per (level, cell)
9
+ catalog/objects.parquet <- the identity index, one row per object
10
+ level=0/part-00000.parquet <- the geometry, finest level
11
+ level=1/part-00000.parquet
12
+ level=2/part-00000.parquet
13
+
14
+ Writing one::
15
+
16
+ import trimesh
17
+ from obstore.store import LocalStore
18
+ import fabriks
19
+
20
+ objects = {1: trimesh.creation.icosphere(radius=4.0), 2: ...}
21
+ manifest = fabriks.write_meshes(
22
+ objects,
23
+ LocalStore("/data"), # or an S3Store, or fabriks.DirectoryStore
24
+ prefix="my-collection",
25
+ cell_size=(128, 128, 64), # in voxels, in your data's own component order
26
+ )
27
+
28
+ Reading it back::
29
+
30
+ collection = fabriks.open_collection(LocalStore("/data"), "my-collection")
31
+ for entry in collection.plan(camera=fabriks.Camera.perspective((0, 0, 500), fov_y=0.8, viewport_height=1080)):
32
+ cell = collection.read_cell(entry.level, entry.cell)
33
+ draw(cell.vertices, cell.faces)
34
+
35
+ sphere = collection.object_mesh(1) # one object, reassembled across its cells
36
+
37
+ Coordinates
38
+ -----------
39
+ **fabriks addresses components by position, never by name.** Vertices, ``cell_size`` and the
40
+ ``bbox_*`` columns are components 0, 1 and 2, and nothing in the writer, the octree or the
41
+ planner asks what they mean. Feed them in whatever order your data already has -- meshes off a
42
+ ``(z, y, x)`` volume stay ``(z, y, x)`` -- as long as you feed them *consistently*, and the
43
+ octree comes out the same either way.
44
+
45
+ The ``x``/``y``/``z`` in the ``bbox_min_x`` column names are labels for those three slots,
46
+ fixed by the Parquet schema a server checks. They are not a claim about which physical axis
47
+ each slot holds, and the format makes no such claim anywhere: naming these axes is a statement
48
+ about how the collection relates to the image it came from or the coordinate graph it sits in,
49
+ which belongs to whatever owns that coordinate system rather than to `fabriks.json`.
50
+
51
+ An order mistake here cannot misplace geometry: clipping and quantization read the same
52
+ ``cell_size``, so a mismatched one yields a differently *shaped* octree rather than displaced
53
+ vertices. Still worth matching ``cell_size`` to the source array's chunk shape, in whatever
54
+ order that shape is in -- a cell that matches the chunking means a viewer fetching image chunks
55
+ and mesh cells pulls the same regions.
56
+
57
+ Simplification
58
+ --------------
59
+ A coarse level is made by a pluggable backend, named the way a codec is: ``"QUADRIC"`` is the
60
+ default, backed by ``fast-simplification`` -- it collapses to the quadric-optimal shape while
61
+ pinning every vertex on the cut boundary at exactly its input position, which is what makes
62
+ ``boundary: LOCKED`` provable rather than intended. ``"GREEDY"`` is a pure-numpy alternative,
63
+ useful where a heavily pinned boundary stops the quadric collapse reaching a budget::
64
+
65
+ fabriks.build_collection(objects, cell_size=..., simplifier="GREEDY")
66
+ fabriks.build_collection(objects, cell_size=..., simplifier=fabriks.GreedyEdgeCollapse())
67
+ fabriks.build_collection(objects, cell_size=..., decimation=fabriks.Decimation.half())
68
+
69
+ Pass the name to pick a backend, an instance to configure one, or your own object providing
70
+ ``simplify`` -- see :mod:`fabriks.simplifiers`.
71
+
72
+ How much survives each level is :class:`Decimation`, defaulting to a quarter. Whatever it is,
73
+ the manifest declares what was actually done: a ratio and its declaration are required to
74
+ agree, because nothing downstream can re-derive one from the other.
75
+
76
+ The byte format is documented in :mod:`fabriks.codecs`; the boundary and decimation arguments in
77
+ :mod:`fabriks.geometry`; the tree layout in :mod:`fabriks.manifest`.
78
+ """
79
+
80
+ from fabriks.build import MeshCollection, build_collection, choose_cell_size
81
+ from fabriks.codecs import (
82
+ QUANT_MAX,
83
+ BlobCodec,
84
+ MeshoptCodec,
85
+ RawCodec,
86
+ codec_for,
87
+ decode_indices,
88
+ decode_positions,
89
+ encode_indices,
90
+ encode_positions,
91
+ )
92
+ from fabriks.errors import (
93
+ FabriksError,
94
+ FormatError,
95
+ MissingExtraError,
96
+ PartitioningError,
97
+ UnfinishedCollectionError,
98
+ )
99
+ from fabriks.frames import (
100
+ DEFAULT_ROW_GROUP_BYTES,
101
+ REQUIRED_COLUMNS,
102
+ arrow_schemas,
103
+ validate_columns,
104
+ )
105
+ from fabriks.geometry import decimate_fixed, snap_boundary
106
+ from fabriks.manifest import (
107
+ BOUNDARY_LOCKED,
108
+ CELL_CATALOG_PATH,
109
+ CODEC_MESHOPT,
110
+ CODEC_NONE,
111
+ COMPRESSION_NONE,
112
+ COMPRESSION_ZSTD,
113
+ DECIMATION_CUSTOM,
114
+ DECIMATION_EIGHTH,
115
+ DECIMATION_HALF,
116
+ DECIMATION_QUARTER,
117
+ INDICES_UINT32,
118
+ MANIFEST_NAME,
119
+ OBJECT_CATALOG_PATH,
120
+ POSITIONS_UINT16_QUANTIZED_PER_CELL,
121
+ SPEC_VERSION,
122
+ Decimation,
123
+ Encoding,
124
+ FileEntry,
125
+ Grid,
126
+ Manifest,
127
+ level_part_path,
128
+ level_prefix,
129
+ )
130
+ from fabriks.octree import cell_box, morton_decode, morton_encode, morton_encode_one
131
+ from fabriks.planner import Camera, plan_cells
132
+ from fabriks.reader import (
133
+ CellEntry,
134
+ Collection,
135
+ DecodedCell,
136
+ ObjectEntry,
137
+ aopen_collection,
138
+ open_collection,
139
+ )
140
+ from fabriks.simplifiers import (
141
+ SIMPLIFICATION_DEFAULT,
142
+ SIMPLIFICATION_GREEDY,
143
+ SIMPLIFICATION_QUADRIC,
144
+ GreedyEdgeCollapse,
145
+ QuadricSimplifier,
146
+ Simplified,
147
+ Simplifier,
148
+ simplifier_for,
149
+ )
150
+ from fabriks.sources import HasVerticesAndFaces, Mesh, MeshSource, coerce_mesh
151
+ from fabriks.stores import (
152
+ AsyncReadable,
153
+ DirectoryStore,
154
+ FabriksStore,
155
+ MemoryStore,
156
+ RangeReadable,
157
+ StoreFile,
158
+ )
159
+ from fabriks.verify import Check, VerifyReport, verify
160
+ from fabriks.writer import awrite_collection, write_collection, write_meshes
161
+
162
+ __all__ = [
163
+ "BOUNDARY_LOCKED",
164
+ "CELL_CATALOG_PATH",
165
+ "CODEC_MESHOPT",
166
+ "CODEC_NONE",
167
+ "COMPRESSION_NONE",
168
+ "COMPRESSION_ZSTD",
169
+ "DECIMATION_CUSTOM",
170
+ "DECIMATION_EIGHTH",
171
+ "DECIMATION_HALF",
172
+ "DECIMATION_QUARTER",
173
+ "DEFAULT_ROW_GROUP_BYTES",
174
+ "INDICES_UINT32",
175
+ "MANIFEST_NAME",
176
+ "OBJECT_CATALOG_PATH",
177
+ "POSITIONS_UINT16_QUANTIZED_PER_CELL",
178
+ "QUANT_MAX",
179
+ "REQUIRED_COLUMNS",
180
+ "SIMPLIFICATION_DEFAULT",
181
+ "SIMPLIFICATION_GREEDY",
182
+ "SIMPLIFICATION_QUADRIC",
183
+ "SPEC_VERSION",
184
+ "AsyncReadable",
185
+ "BlobCodec",
186
+ "Camera",
187
+ "CellEntry",
188
+ "Check",
189
+ "Collection",
190
+ "Decimation",
191
+ "DecodedCell",
192
+ "DirectoryStore",
193
+ "Encoding",
194
+ "FabriksError",
195
+ "FabriksStore",
196
+ "FileEntry",
197
+ "FormatError",
198
+ "GreedyEdgeCollapse",
199
+ "Grid",
200
+ "HasVerticesAndFaces",
201
+ "Manifest",
202
+ "MemoryStore",
203
+ "Mesh",
204
+ "MeshCollection",
205
+ "MeshSource",
206
+ "MeshoptCodec",
207
+ "MissingExtraError",
208
+ "ObjectEntry",
209
+ "PartitioningError",
210
+ "QuadricSimplifier",
211
+ "RangeReadable",
212
+ "RawCodec",
213
+ "Simplified",
214
+ "Simplifier",
215
+ "StoreFile",
216
+ "UnfinishedCollectionError",
217
+ "VerifyReport",
218
+ "aopen_collection",
219
+ "arrow_schemas",
220
+ "awrite_collection",
221
+ "build_collection",
222
+ "cell_box",
223
+ "choose_cell_size",
224
+ "codec_for",
225
+ "coerce_mesh",
226
+ "decimate_fixed",
227
+ "decode_indices",
228
+ "decode_positions",
229
+ "encode_indices",
230
+ "encode_positions",
231
+ "level_part_path",
232
+ "level_prefix",
233
+ "morton_decode",
234
+ "morton_encode",
235
+ "morton_encode_one",
236
+ "open_collection",
237
+ "plan_cells",
238
+ "simplifier_for",
239
+ "snap_boundary",
240
+ "validate_columns",
241
+ "verify",
242
+ "write_collection",
243
+ "write_meshes",
244
+ ]