Skip to documentation
DocumentationAll documentsEnglish

FACETIZE(nged)

NAME

facetize - Creates __new_object__ using __old_object__ as a guide, creating an evaluated NMG or BoT planar approximation of the original shape.

On this page

SYNOPSIS

facetize [-h] [-v] [-q] [-n] [-r] [-j jobs] [-s suffix] [-p prefix] [--in-place] [--max-time #] [--max-pnts #] [--resume] [--methods m1,m2,...] [--method-opts METHOD opt1=val opt2=val...] [--no-empty] [--log-file filename] [--nmg-booleval] [--disable-fixup] [--perturb] [--no-perturb] [--perturb-sa-tol #] [--perturb-vol-tol #] [--tolerate-failures] [-B -t threshold] {old_object new_object}

DESCRIPTION

The facetize operation in BRL-CAD is, broadly speaking, the processing of creating an explicit planar approximation of a CSG volume by evaluating the boolean expressions used to combine a set of explicit and implicit solid primitives. It is the core operation necessary for creating triangle based meshes from BRL-CAD geometry.

The facetize command can attempt to produce either triangle-only BoT objects, or N-Manifold Geometry (NMG) objects, but generally speaking BoT generation will have a higher success rate than NMG. BoTs are also more useful when exporting to formats such as STL and OBJ - by default BoT output is what facetize will produce.

In general Boolean evaluation of meshes is a very difficult problem, and there are also some specific considerations when it comes to preparing geometry for solid shotline raytracing that require more effort than producing a visualization mesh. It is recommended to use the lint command, both to verify input objects are well behaved before facetization and to check facetize outputs for any potential issues. Often times either the original CSG geometry definitions will need adjustment to avoid coplanar faces, or mesh editing is required to resolve problematic triangle configurations.

By default all specified existing objects will be combined into a single mesh, but that is often undesirable when working within BRL-CAD - information stored on region combs such as color will be lost when converting in this fashion. The -r option will introspect into the specified objects and perform facetization on a per-region basis. (If the specified input has no regions in its tree, a normal facetization to a single object is performed instead.) The output will be a new hierarchy that references the facetized regions but retains the properties of parent regions. Users looking to interact visually with a shaded display of a model will likely find the -r output useful for that purpose.

There are a number of different verbosity levels available for the facetize command. One or multiple specifications of the -v flag will increase reporting detail. Because full output from facetize can be quite verbose, the user has the option to specify a log file with the --log-file option - this will capture all output from the command and allow for more detailed scrutiny of what took place after a conversion has finished.

Output Characteristics and Processing Controls

By default the facetize command attempts to be non-destructive when operating on objects - it will not rename or replace any existing geometry in normal operational modes, and will adjust its naming accordingly when producing new objects. However, if a user wants to replace objects with facetized replacements, this may be accomplished by specifying the --in-place option. Note that this is a destructive operation - the original object definitions will be overwritten - so use with care!

Users may be a bit startled to see empty (0 face, 0 vertices) BoTs produced by a facetize command, but this is in fact expected behavior when a boolean option legitimately results in an empty mesh. For example, if a sphere in a comb is subtracted from itself, and no other geometry is referenced, the result is a zero (empty) volume. The lint command can be used to identify such BoTs - if they are produced, it is often an indication the original CSG definition has some sort of problem. These empty outputs can be suppressed by specifying the --no-empty option, but the recommended course is to determine what about the original geometry produced them and either correct any issues or (if the shapes truly are not intended to be present) remove the original CSG definitions producing them.

It may happen that a conversion fails part way through the process. This can happen due to user intervention, resource exhaustion, or simply as a consequence of a bug in the conversion logic. If this happens, the intermediate state of the conversion will be stored by BRL-CAD in its cache directory, and the interrupted process may be resumed by re-running facetize with the --resume option. (If a conversion fails and the command is re-run without specifying --resume, previous work will be cleared and the process will start over from the beginning.)

In normal operation, when converting to BoT output there are post-processing routines that try to identify and automatically fix certain categories of geometric flaws that can crop up during Boolean evaluation. If a user finds that they are getting unexpected output for a particular input, and the log indicates the repair step was run, one option available is to repeat the conversion with these repair steps disabled via the --disable-fixup flag. Repair should only be disabled if there is a problem - coplanar subtractions frequently result in thin triangle artifacts lingering after Boolean evaluation due to the limitations of floating point math, and in at least some cases the fixup routines are able to deal with these without requiring manual intervention. (These routines will not always work, so checking of outputs after a conversion with the lint command to identify BoTs with potentially problematic features is still recommended - see the lint man page for more details.)

By default facetize treats failed primitive tessellations, failed leaf preparation, and failed Boolean subtree evaluations as command failures. This is deliberate: a BoT or NMG produced after silently omitting input components can be hard to distinguish from a complete result. The --tolerate-failures option restores the older partial-output behavior as an explicit user choice. When this option is used, facetize will omit components it cannot successfully evaluate and continue when it can still produce some output. If any failures are tolerated, facetize prints a final warning that the result is partial and not a complete representation of the input, along with a capped list of omitted components; the full list is written to the log file.

By default, the Manifold BoT path can make use of a coplanarity-avoidance perturbation retry for eligible primitives. In per-region mode, facetize first evaluates the unperturbed BoT and validates it against the source CSG with Crofton metrics; perturbed variant tessellation is only attempted if those metrics indicate the initial result is outside tolerance. In non-region BoT mode, perturbation is disabled by default but can be enabled explicitly with --perturb. This helps avoid difficult Boolean edge cases where the same primitive participates in both additive and subtractive roles and coplanar/sliver configurations can lead to problematic near-tolerance triangles. If needed, this behavior can be disabled with --no-perturb.

When the perturbation step is active, per-region facetize validates the initial Boolean output against the original CSG geometry using a Crofton stochastic raytrace. The default tolerance thresholds that trigger a perturb retry are 10% for both surface area and volume; these can be adjusted with --perturb-sa-tol and --perturb-vol-tol. At the end of a per-region facetization run facetize prints a concise validation summary listing how many regions passed, triggered a perturb retry, or encountered one of the following noteworthy conditions:

Unbounded halfspace (validation unavailable): Crofton surface-area and volume comparisons require a finite sampling domain. A standalone halfspace, or another CSG result without finite bounds, is therefore not sampled and is counted as having validation unavailable. A bounded object intersected with or subtracted by a halfspace can still be validated because its finite operand supplies the sampling bounds.

Sub-mm / few-hit bypass (accepted with note): When the Crofton sampler finds only a very small number of ray-surface intersections (below an internal threshold of 50 crossings), the sampling noise alone would exceed 14% relative error, making any SA comparison meaningless. Geometry in this category is typically sub-millimetre in cross-section (e.g., a TGC with a radius under 0.2 mm) but the stochastic sampler has confirmed that some geometry is present. The BoT conversion is accepted and the region is counted separately in the summary. Users should verify that such extreme geometry reflects actual modeling intent rather than an accidental near-degenerate primitive.

Zero-hit replacement: When the Crofton sampler fires rays but records zero intersections with the CSG geometry while the corresponding BoT is non-empty, facetize concludes that the Boolean evaluation most likely produces empty geometry (for example, a subtractor that fully engulfs the base object). In this case the non-empty BoT is discarded and replaced with an empty BoT to match the expected raytrace behavior. If this replacement appears unexpected for a given region, the lint command can be used to inspect the result.

Perturb topology shift (accepted with note): After a perturb retry, if the Crofton raytrace of the perturbed CSG returns zero while the perturbed BoT is non-empty, the perturbation itself may have shifted the geometry topology (for example, a subtractor that now fully engulfs the base in parametric space). The BoT output is still accepted; the lint command can be used to inspect the result.

Persistent validation mismatch: When both the P1 and P2 Crofton comparisons exceed the tolerances for reasons other than sub-mm geometry (for example, union-coplanar shared faces or curved-surface volume sensitivity), a WARNING is reported. The BoT conversion is still written out and the lint command should be used to assess the output.

Different tolerance settings will create finer or coarser meshes. See the tol man page for more details.

Long-Running Tessellation and Recovery

Primitive tessellation is performed in a child process against a private working copy of the database in the BRL-CAD cache. The original database is not modified as individual primitive meshes are generated. Only after the conversion succeeds are the requested results transferred from the working database. This separation also permits an interrupted conversion to retain its intermediate state for use with --resume.

The parent command sends primitive names to a small pool of persistent tessellation processes. Each child reports a result for every name, so a timeout, conversion failure, or child-process crash can be associated directly with the affected primitive. A child is restarted when necessary and processing continues with the next name; the parent does not subdivide and retry the whole group to discover which object failed. Unless output is suppressed with --quiet, long tessellation batches also report their completed-object count and active-worker state at approximately five-second intervals.

By default, facetize uses at most two worker processes and only enables the second when both CPU and memory information indicate it is safe. It reserves the larger of one GiB or one quarter of total physical memory for the rest of the system. Starting another job also requires at least 512 MiB beyond that reserve, or the largest worker resident-memory measurement seen so far if that is greater. If the platform cannot report the required memory information, facetize falls back to one worker. The available CPU count is divided among worker processes and is also imposed as the thread limit inside each worker, preventing nested algorithms from independently using all CPUs. --jobs changes the maximum process count; it does not bypass the memory admission checks.

Per-region BoT conversion uses this worker policy for both independent CSG validation and initial Manifold Boolean evaluation. When more than one worker is available, persistent validation processes each open their own read-only handle to the original database and compute Crofton surface-area and volume references for different regions. Persistent Boolean processes then evaluate different region trees using independent read-only handles to one shared snapshot of the tessellated working database. That snapshot also serves as the rollback checkpoint, so increasing --jobs does not create additional full database copies. This process isolation avoids sharing mutable raytrace preparation or database state between concurrent evaluations. Each result remains associated with the requested region name. The parent commits completed BoTs through one writer and continues to perform hierarchy changes, validation decisions, and any perturb retries serially. A one-worker run retains the established in-process order and avoids the snapshot phase.

Validation and Boolean workers report their completed-region count and active-worker state approximately every five seconds. When --max-time is specified, it also bounds each parallel CSG reference or Boolean request; a timed-out process is terminated, and the failure is associated with that region. Failure or timeout of supplementary CSG validation does not cause unrelated regions to be retried.

Database updates use a separate write handshake. After preparing a mesh in memory, a child announces that it is ready to write and reports the approximate mesh size and its current resident memory, then waits. The parent grants write permission, the child acknowledges when it is starting the write, and the child explicitly reports when the update is complete. Consequently, the normal per-object tessellation limit, including --max-time and method-specific limits, applies to mesh preparation and does not interrupt an acknowledged write.

With multiple workers, primitive tessellation children write to small staging databases rather than modifying the shared working database. Region Boolean children read one immutable cache-local snapshot while completed results are committed to the working database. The snapshot doubles as the recovery checkpoint and is opened independently by each worker; it is not duplicated per worker. For very large files, snapshot preparation reports the amount copied and elapsed time at five-second intervals. A region result is first completed in memory and enters the write handshake only when it is ready to replace the prior staged result. After a child reports a completed staging write, the parent submits that result to a single persistent writer process. The writer announces that it is ready, waits for the parent’s permission, acknowledges that it is starting the write, transfers the result through one persistent working-database handle, and reports completion. This permits tessellation and initial region Boolean evaluation to proceed in parallel without concurrent database allocation updates or repeated full directory scans, while allowing the parent to supervise the canonical database write itself. With one worker, the established direct path avoids the extra staging I/O and database snapshot.

Before the first primitive conversion, the parent measures write throughput on the same cache filesystem as the working database. It writes a temporary file in 1 MiB chunks until approximately one second has elapsed or 128 MiB has been written, then removes the file immediately. Successful mesh writes of at least 1 MiB subsequently refine this profile. For each database update, the parent allows ten times the projected write time, with a minimum of five seconds and a maximum of five minutes. This measured allowance protects legitimate long writes on slow storage while still detecting a genuinely stalled update.

If a child fails before acknowledging that its write has started, the working database is known to be unchanged and no rollback is needed. In parallel mode, a failure during a child write affects only that worker’s disposable staging database, so the failed object is reported and the worker can be restarted without replaying unrelated objects. A serial child failure during a direct write, or a writer-process failure after acknowledging write start, is ambiguous because the working database may contain a partial update. In those cases facetize restores its cache-local checkpoint and replays only the conversions not already tied to a specific failure. The original database remains untouched during this recovery.

Options

-h, --help

Print help and exit.

-v[v..], --verbose

Prints extra (verbose) information in results. May be overridden by the --quiet flag.

-q, --quiet

Suppress all output (overrides verbosity flag.)

-n, --nmg-output

Instructs facetize to produce NMG solids rather than BoT solids.

-r, --regions

Rather than converting all specified inputs to one top level object, walk specified trees and individually convert regions to facetized objects. This mode is useful when wanting to display models in shaded mode while preserving color and region ID properties. If no regions are present a normal conversion is performed instead.

-j, --jobs #

Set the maximum number of facetize worker processes. A value of 1 forces serial processing. The default value of 0 selects a conservative automatic limit based on available CPUs and memory. Memory checks may delay or reduce parallel work even when a larger value is requested. In per-region BoT mode the same limit controls parallel CSG reference sampling and initial Manifold Boolean evaluation.

-s, --suffix

User specified suffix to use avoiding naming conflicts (naming conflict avoidance is needed when creating objects in -r mode.)

-p, --prefix

User specified prefix to use avoiding naming conflicts (naming conflict avoidance is needed when creating objects in -r mode.)

--in-place

Replace the specified object(s) with their facetizations. (WARNING: this option is destructive and will change pre-existing geometry!)

--max-time #

Maximum time to spend per object (in seconds). Default is method specific. Note that specifying shorter times may cut off conversions (particularly using sampling methods) that could succeed with longer runtimes. Per-method time limits can also be adjusted to allow longer runtimes on slower methods.

--max-pnts #

Maximum number of pnts per object to use when applying ray sampling methods.

--resume

Resume an incomplete facetization process (will utilize cached data from a previous run rather than starting from scratch.) Re-running without this option will clear any old data and start from the beginning.

--methods

Accepts a comma separated list of one or more facetization methods to use. The default tries NMG tessellation first, Manifold Dual Contouring (MDC) second, and SPSR as a final fallback. Other listed methods may be selected explicitly if a user wants to try a specific methodology.

--method-opts

This option can be used to pass parameter values to specific facetize methods. The argument format is "METHOD opt1=val1 opt2=val2 …​". See the --help output for which methods and parameters are supported by facetize.

--no-empty

Do not write out empty BoT objects when a Boolean evaluation results in an empty mesh.

--log-file

Specify a log file in which to store the full verbose output of a facetization process. This is recommended for large or long running facetize runs to allow users to better understand what steps were taken and what problems might have arisen.

--nmg-booleval

Use the libnmg boolean evaluation algorithm even when producing BoT output. This can be less robust, but may yield cleaner results for some coplanar cases.

--disable-fixup

By default, BoT facetization will attempt to clear certain categories of undesirable triangles from outputs. Specifying this option will skip that repair attempt.

--perturb

Enable the coplanarity-avoidance perturbation step. In per-region mode this behavior is enabled by default; in non-region BoT mode it must be requested explicitly. This option conflicts with --no-perturb.

--no-perturb

Disable the coplanarity-avoidance perturbation retry machinery in BoT Manifold Boolean evaluation. This option conflicts with --perturb.

--perturb-sa-tol #

Surface-area percentage threshold (0–100) that triggers the coplanarity-avoidance perturb retry when the per-region Crofton-sampled CSG surface area differs from the initial facetized BoT surface area by more than this amount. Default is 10 (percent).

--perturb-vol-tol #

Volume percentage threshold (0–100) that triggers the coplanarity-avoidance perturb retry when the per-region Crofton-sampled CSG volume differs from the initial facetized BoT volume by more than this amount. Default is 10 (percent).

--tolerate-failures

Continue after failed primitive or subtree evaluations and generate a partial result when possible. Any omitted components are reported at the end of the run, and the resulting output should be treated as incomplete until the reported failures are understood. This option is useful for diagnosis or for extracting a best-effort mesh from a very large model, but should not be used when a complete representation is required.

-B

Experimental non-overlapping facetization to BoT objects for union-only brep comb trees.

-t threshold, --threshold threshold

Experimental overlap-threshold length used by -B mode.

Facetization Methods

In broad, there are two stages to a facetization process. The first stage is the generation of mesh representations for individual geometric primitives - implicit ELL, ARB8, TOR, etc. solids must be represented by mesh approximations before they can become part of an evaluated mesh. Additionally, inputs that are already meshes are checked for suitability - all input meshes, whether generated from implicit shapes or pre-existing as BoTs, must be properly manifold before they can be used for facetization. Once all solids have been successfully converted, the next step is to evaluate the Boolean tree hierarchy by unioning, subtracting or intersecting the various meshes together to produce the evaluated shapes.

The process of individual primitive to mesh conversion can sometimes be problematic - routines may take extremely long lengths of time trying to resolve a conversion problem. In order to avoid the process hanging indefinitely with no progress, a timeout is established that limits how long each individual conversion process should take. Various methods have defaults defined internally, so this isn’t something the user normally needs to concern themselves with, but if they wish to set a limit themselves (either allowing more time or forcing shorter cycles) they can do so with the --max-time option.

It can be difficult to produce a mesh from a primitive shape. Simply waiting longer for results often isn’t practical or even the right answer - indeed, infinite looping has been observed in some primitive conversion cases. To work around these limitations, BRL-CAD provides multiple methods that can be used to attempt mesh production in case other methods fail. We deliberately do not document those methods in detail here - they are subject to change as new alternatives are identified that can produce better results. What we do document is how to use the facetize command to see what methods are currently available and control them. The -h option will list, at the end of its output, information about all currently available methods and what controls they offer. The facetize option --methods can be used to restrict the facetize command to a particular subset of the available methodologies, and the --method-opts option is used to pass specific parameters to a specific method.

Because many of the facetization methods are sampling based (the raytracer is used to sample the volume) a top level control is available to specify the maximum number of points to use when generating inputs for such methods. (More points generally means a better conversion at the expense of memory and runtime.)

Primitive tessellation also applies internal minimum tolerance floors to avoid pathological "triangle bombing" (very small tolerance requests producing extreme triangle counts with little practical benefit for modeling/raytrace fidelity). Advanced users who explicitly want to bypass those defaults may set environment variables RT_PRIM_MIN_ABS_TOL and/or RT_PRIM_MIN_NORM_TOL to positive floating-point values before running facetize. These overrides are an expert-use escape hatch: lower floors can substantially increase memory/runtime cost and may produce extremely high triangle counts.

EXAMPLES

Example 1. Create a facetized BOT version of an existing object.

The example shows the use of the facetize command to create a facetized BOT version of an existing object (old_object) and renaming that facetized object (new_object).

mged>facetize region1.r region1.bot

Example 2. Facetize all regions in a hierarchy.

This runs the per region conversion on all regions under the "model" assembly and creates a new conversion hierarchy under model_facetized.

mged>facetize -r model model.f

Example 3. Facetize all regions in a hierarchy, attempting only NMG conversion.

This runs the NMG approach per region conversion on all regions, but in the case of failure will not attempt any fallback conversion methods.

mged>facetize -r --methods NMG model model.f

Example 4. Retry failed conversion objects in a previous facetization attempt with new methodology.

This resumes a failed conversion of model.

mged>facetize -r --resume model model.f

Example 5. Generate a partial BoT from a difficult tree.

This attempts to facetize large_model while explicitly allowing failed primitives or subtrees to be omitted. The final result should be inspected carefully: if any failures are tolerated, facetize will report that the output is partial.

mged>facetize --tolerate-failures large_model large_model.partial.bot

Example 6. Refine a Manifold Dual Contouring conversion

This selects MDC directly and requests a finer cell size with a larger ray budget than the default:

mged>facetize --methods MDC --method-opts "MDC feature_size=0.1 max_rays=400000" ellipse.r ell.bot

Smaller feature sizes increase mesh detail, ray count, memory use, and runtime.

USEFUL TRICKS

These are some useful commands related to the facetization process.

Example 7. List invalid BoT objects below a comb

Use lint -I to report on invalid objects below a comb.

mged>lint -I model.f

Example 8. Pre-extrude Plate Mode BoTs

Use search -exec to extrude all plate mode bots before attempting a facetize operation.

mged>search model.f -type bot -type plate -exec bot extrude -i "{}" ";"

Implementation Details

The current implementation of facetize launches primitive facetization operations in a subprocess, to allow for recovery if individual primitives crash, infinite loop, or otherwise trigger what would otherwise be catastrophic behavior. This means that it is essential the operating environment allow the parent program to launch those subprocesses - otherwise, conversion will fail.

Unlike previous versions of facetize, this version (in BoT mode) will only facetize each primitive once - if a primitive is instanced repeatedly in multiple combs, it will use the same BoT to represent all of those instances. If for some reason this is not desired behavior, the user should first prepare the geometry by making all instances unique with xpush.

AUTHOR

BRL-CAD Team

BUG REPORTS

Reports of bugs or problems should be submitted via electronic mail to devs@brlcad.org