How are the resulting parts from CSG operations ordered?

I want to know what order the parts from the CSG operations in geometry service are generated.

There does not appear to be much info on how these parts are generated.

I could try sorting the parts myself after they are generated, but I would rather know how they are generated to begin with.

1 Like

Could you be more specific or provide an example? What do you mean by “generated”?

Suppose you use geometry service’s “SubtractAsync”, and cut a cylinder part in half with a very thin part that acts as the plane which cuts the cylinder part in half. Subtractasync will then return a table containing all the parts of the resulting operation. In this case, the two halves of the cylinder. What I want to know is in what order do the halves appear in that table. Is the leftmost half the first element? Is the table sorted by mass? That’s what I wish to know.

For a call to GeometryService like:

local results = GeometryService:SubtractAsync(original, subtractList)

It appears the order of PartOperation in the results array are based on their relative offset from original, first by lowest relative X, then lowest relative Y, then lowest relative Z.

Here, I’ve color coded the PartOperations based on their index in the results table with Red being the first index and Blue being the last index. The small axes cones in the lower center of the image represent the orientation of the original Part with each cone facing the positive direction on its axis.

Here’s another example, however the original Part was rotated 90 degrees left before calling SubtractAsync (the subtractList Parts were not modified):

I’m not 100% certain this will always be the case. The order may in fact be undefined in the general case. Here’s the code I used to make these images if you want to try something yourself. Let me know if you find a case that deviates from the pattern I described above.

Simple Subtract Code
--[[ Hierarchy
Model
	Subtract (Folder containing Parts)
	Results (Empty Folder)
	Script (Script with the following code)
	Original (Part)
]]
local GeometryService = game:GetService("GeometryService")

task.wait(3)

local originalPart = script.Parent.Original
local subtractFolder = script.Parent.Subtract

local results = GeometryService:SubtractAsync(originalPart, subtractFolder:GetChildren())

originalPart.Transparency = 1
subtractFolder:ClearAllChildren()

for i, resultPart in results :: { PartOperation } do
	
	local hue = (6 / 9) * (i - 1) / (#results - 1)
	
	resultPart.Name = "Result" .. i
	resultPart.Color = Color3.fromHSV(hue, 1, 1)
	resultPart.UsePartColor = true
	resultPart.Parent = script.Parent.Results
	
end

Yep, that’s correct. Parts are sorted lexicographically by their min bounding box corner (X then Y then Z). Note that this happens in the primary part’s local coordinate frame.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.