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.
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.
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()
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")
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()
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()
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()