Examples

A basic example of how to use PLGPython inside PointKit Scan is shown below. This example loads a scan, aligns the scan, and sends a flag to PointKit Scan to read in the meshes.

Basic Examples

Loading a scan, aligning it, and passing the meshes back to PointKit:

import PointKitPy as pk
scriptingInterface = pk.Scripting()
scriptingInterface.Load(r"C:\path\to\scan.pbn")  # Load a PBN file containing multiple scans
scriptingInterface.AlignFast()
POINTKIT_MESHES = scriptingInterface.GetMeshes()  # or scriptingInterface.mMeshList

Running Cleanup on a folder of .ply files, decimating them, and saving them to a new folder:

import PointKitPy as pk
scriptingInterface = pk.Scripting()
# If you wanted to wait until a certain number of .ply files (e.g. 5) exist in the folder,
# you could use the following code:
# scriptingInterface.MonitorDirectory(r"C:\path\to\scans", 5, r".*\.ply")  # The filter is regex.
scriptingInterface.Load(r"C:\path\to\scans")  # Load a folder containing multiple .ply files
scriptingInterface.Cleanup()
scriptingInterface.DecimateByRadius(0, True) # Auto-calculate the radius and use voxel downsampling
scriptingInterface.Save(r"C:\path\to\output")

PLGPython automatically keeps track of the meshes that you have loaded in, so you can call functions on the meshes without needing to pass them in as arguments, just like PointKit Scan’s mesh list. If you want to only work with a subset of the meshes, you can use the scriptingInterface.mMeshList list to access the meshes that were returned from the last function call. This is a list of PLGMeshExt objects that you can manipulate as you wish. To get a copy of the meshes that are currently loaded in, you can use the scriptingInterface.GetMeshes() function.

Complex Examples

Finalize PointKit Meshes

Finalize.py
 1import PointKitPy as pk
 2
 3si = pk.Scripting()
 4si.mMeshList = POINTKIT_MESHES
 5
 6print("Running Finalize...")
 7ok = si.Finalize(
 8    enableCombine=True,
 9    combineMethod="Voxel",
10    combineVoxelSize=0.08,
11    meshResolution="High",
12    pointsToMeshMethod="Poisson",
13    trimFactor=2,
14    smoothIter=3,
15    enableHoleFilling=True,
16    maxHoleFillArea=0.02
17)
18print("Finalize result:", ok)
19
20POINTKIT_MESHES = si.GetMeshes()

LODPackager: Save 3 levels of decimation to disk

LODPackager.py
 1import os
 2import PointKitPy as pk
 3
 4OUT_ROOT = r"C:\PointKit\exports\MyScene"
 5LODS = [("LOD0", 60.0), ("LOD1", 30.0), ("LOD2", 10.0)]
 6
 7os.makedirs(OUT_ROOT, exist_ok=True)
 8
 9for name, keep in LODS:
10    si = pk.Scripting()
11    si.mMeshList = POINTKIT_MESHES
12    print("Decimating", name, "keep", keep)
13    si.DecimateRandom(keepPercentage=keep)
14    si.Smooth(nIter=1)
15    out_dir = os.path.join(OUT_ROOT, name)
16    os.makedirs(out_dir, exist_ok=True)
17    si.Save(path=out_dir, ext="ply")

Run Fast, Standard if fail, Optimize Alignment, then Finalize

MultiAlignThenFinalize.py
 1import PointKitPy as pk
 2
 3si = pk.Scripting()
 4si.mMeshList = POINTKIT_MESHES
 5
 6ok = True
 7
 8if len(si.mMeshList) < 2:
 9    print("Need at least 2 meshes for alignment.")
10else:
11
12    print("Pass 1: AlignFast on moving -> locked")
13    ok = si.AlignFast()
14    print("AlignFast ok:", ok)
15
16    if not ok:
17        print("Fallback: AlignStandard on moving -> locked")
18        ok = si.AlignStandard()
19        print("AlignStandard ok:", ok)
20
21    if ok:
22        print("Refine: OptimizeAlignment on all")
23        ok = si.OptimizeAlignment()
24        print("OptimizeAlignment ok:", ok)
25
26print("Finalize after alignment")
27ok = si.Finalize(
28    enableCombine=True,
29    combineMethod="Voxel",
30    combineVoxelSize=0.08,
31    meshResolution="High",
32    pointsToMeshMethod="Poisson",
33    trimFactor=2,
34    smoothIter=3,
35    enableHoleFilling=True,
36    maxHoleFillArea=0.02
37)
38print("Finalize OK: ", ok)
39
40POINTKIT_MESHES = si.GetMeshes()

Run finalize on each mesh in PointKit

perMeshFinalize.py
 1import PointKitPy as pk
 2
 3si = pk.Scripting()
 4si.mMeshList = POINTKIT_MESHES
 5original = si.GetMeshes()
 6
 7processed = []
 8for idx, m in enumerate(original):
 9    print("Processing mesh index:", idx)
10    si.ClearMeshList()
11    si.mMeshList = [m]
12
13    ok = si.Cleanup()
14    print("  Cleanup ok:", ok)
15
16    ok = si.Finalize(
17        enableCombine=False,
18        meshResolution="Standard",
19        pointsToMeshMethod="Poisson",
20        smoothIter=1,
21        enableHoleFilling=True
22    )
23    print("  Finalize ok:", ok)
24
25    part = si.GetMeshes()
26    if len(part) > 0:
27        processed.append(part[0])
28
29print("Reassembling processed meshes")
30si.ClearMeshList()
31si.mMeshList = processed
32
33POINTKIT_MESHES = si.GetMeshes()

Run two finalization options, save to disk, and load the smaller one

smallerFinalize.py
 1import PointKitPy as pk
 2import os
 3
 4si = pk.Scripting()
 5si.mMeshList = POINTKIT_MESHES
 6si.SetLogLevel("All")
 7
 8tmp_root = "C:\\Users\\USERNAME\\Documents\\Scripting Examples\\data" # !! replace with your desired path.
 9os.makedirs(tmp_root, exist_ok=True)
10
11print("Pipeline A: Poisson")
12si.mMeshList = POINTKIT_MESHES
13ok = si.Finalize(
14    enableCombine=True,
15    combineMethod="Voxel",
16    combineVoxelSize=0.08,
17    meshResolution="High",
18    pointsToMeshMethod="Poisson",
19    trimFactor=2,
20    smoothIter=2,
21    enableHoleFilling=True
22)
23print("Finalize A ok:", ok)
24dir_a = os.path.join(tmp_root, "A_poisson")
25os.makedirs(dir_a, exist_ok=True)
26print("Saving A...")
27ok = si.Save(dir_a, ext="ply")
28print("Save A ok:", ok)
29
30print("Pipeline B: Triangulation")
31si.mMeshList = POINTKIT_MESHES
32ok = si.Finalize(
33    enableCombine=True,
34    combineMethod="Voxel",
35    meshResolution="Standard",
36    pointsToMeshMethod="Triangulation",
37    smoothIter=2,
38    enableHoleFilling=True
39)
40print("Finalize B ok:", ok)
41dir_b = os.path.join(tmp_root, "B_triangulation")
42os.makedirs(dir_b, exist_ok=True)
43print("Saving B...")
44ok = si.Save(dir_b, ext="ply")
45print("Save B ok:", ok)
46
47def dir_size(path):
48    total = 0
49    for root, _, files in os.walk(path):
50        for f in files:
51            total += os.path.getsize(os.path.join(root, f))
52    return total
53
54size_a = dir_size(dir_a)
55size_b = dir_size(dir_b)
56print("Size A bytes:", size_a)
57print("Size B bytes:", size_b)
58
59chosen = dir_a if size_a <= size_b else dir_b
60print("Chosen dir:", chosen)
61
62print("Loading chosen into UI...")
63si.Reset()
64ok = si.Load(chosen, filter=r".*\.ply")
65print("Load ok:", ok)
66
67POINTKIT_MESHES = si.GetMeshes()
« Previous