File: brownian_movement.py

package info (click to toggle)
camitk 6.0.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 389,496 kB
  • sloc: cpp: 103,476; sh: 2,448; python: 1,618; xml: 984; makefile: 128; perl: 84; sed: 20
file content (75 lines) | stat: -rw-r--r-- 2,628 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# This is a CamiTK python action
#
# This action displaces the points of a MeshComponent randomly 
# (this is the equivalent of the Shaker tutorial)

import camitk
import numpy as np
from PySide2.QtCore import QTimer

def tick(self:camitk.Action):
    # get the point position as a numpy array
    points = self.mesh.getPointSetAsNumpy();
    percent = self.getParameterValue("Intensity")
    
    # check dimensions
    assert points.ndim == 2 and points.shape[1] == 3, "Input must be an (N, 3) array"
    assert 0 <= percent <= 100, "Percent must be between 0 and 100"

    # Compute bounding box
    min_pt = points.min(axis=0)
    max_pt = points.max(axis=0)
    diag = np.linalg.norm(max_pt - min_pt)
    move_distance = (percent / 100.0) * diag
    
    # Generate random directions per point
    random_vectors = np.random.randn(*points.shape)
    norms = np.linalg.norm(random_vectors, axis=1, keepdims=True)
    directions = random_vectors / norms  # Normalize each row

    # Scale and move
    step_displacements = directions * move_distance
    moved_points = points + step_displacements
        
    # update mesh
    self.mesh.replacePointSet(moved_points)
    
    # compute displacements
    if self.getParameterValue("Show Displacement"):
        total_displacement = np.linalg.norm(moved_points - self.initial_position[self.mesh.getName()], axis=1)
        self.mesh.addPointData("Displacement", total_displacement)
    else:
        self.mesh.setDataRepresentationOff()
    
    # update interval
    interval = self.getParameterValue("Update Intervals")
    self.timer.setInterval(interval)
    
def init(self:camitk.Action):
    self.timer = None
    self.setApplyButtonText("Start Shaking")
    self.initial_position = {}    

def process(self:camitk.Action):
    self.mesh = self.getTargets()[-1]
    
    # store initial position
    if self.mesh.getName() not in self.initial_position:
        self.initial_position[self.mesh.getName()] = self.mesh.getPointSetAsNumpy();
    
    if not self.timer:
        self.timer = QTimer()
        connected = self.timer.timeout.connect(lambda: tick(self))     

    if not self.timer.isActive():
        self.setApplyButtonText("Stop Shaking")
        interval = self.getParameterValue("Update Intervals")
        self.timer.start(interval)
    else:
        self.mesh.replacePointSet(self.initial_position[self.mesh.getName()])
        self.setApplyButtonText("Restart Shaking")
        self.timer.stop()
    
def parameterChanged(self:camitk.Action, name:str):
    if not self.getParameterValue("Show Displacement"):
        self.mesh.setDataRepresentationOff()