summaryrefslogtreecommitdiff
path: root/geom/volume_collision.py
blob: c262a88cdf5e542bc609cfe21e472be3acbfdef0 (plain)
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#for volume interference
from OCC.BRepGProp import *
from OCC.GProp import *

def shape_volume(shape): #should probably be a method of Shape
    '''returns the volume of a TopoDS_Shape or Shape'''
    tmp = GProp_GProps()
    BRepGProp().VolumeProperties(shape, tmp)
    volume = tmp.Mass()
    return volume

def assembly_volume_estimate(parts):
    '''returns the volume of an assembly given a list of parts
    returns a sum of the volumes of each part
    does not consider interference (see assembly_volume_actual)'''
    total_volume = 0
    for part in parts:
        total_volume += part.volume()
    return total_volume

def assembly_volume_actual(parts):
    '''computes the actual volume of an assembly
    interference between two parts tends to decrease the volume'''
    #total_volume = assembly_volume_estimate(parts)
    #box = BRepPrimAPI_MakeBox(Point(0,0,0), Point(1,1,1))
    shape = None
    #FIXME you should actually set no initial shape, and then make an initial shape in the for loop if there isn't one already
    #shape = TopoDS_Shape() #start with nothing
    for part in parts:
        if shape is None:
            shape = part.shapes[0]
        else:
            #is it ok to fuse non-touching objects into the same shape?
            tmp_shape = BRepAlgoAPI_Fuse(shape, part.shapes[0])
            shape = tmp_shape.Shape()
    return shape_volume(shape)

def estimate_interference_volume(parts):
    '''figures out how much volume should be missing from assembly_volume_actual compared to assembly_volume_estimate
    not particularly special or enlightening'''
    total_expected_missing_volume = 0
    interfaces = []
    for part in parts:
        for interface in part.interfaces:
            if interface.connected == True and interface not in interfaces:
                #it's important to go over the interfaces as many times as they are mated
                #because complementary interfaces should have complementary (positive, negative) volumes
                #thus the total resulting volume should be zero if everything has a perfect fit

                #if you disagree:
                ##no_go = False #it's ok
                ##mates = interface.connected
                ##for mate in mates:
                ##    if mate in interfaces:
                ##        no_go = True #not ok, it's already considered
                ##if not no_go:

                total_expected_missing_volume += interface.volume
                interfaces.append(interface) #so we don't count it twice
    return total_expected_missing_volume

#this is the one you want to use after adding a part to an assembly
def estimate_collision_existence(parts, threshold=-1):
    '''determines whether or not there is an illegal collision in the assembly.
    threshold determines how much leeway you're willing to give the assembly. 0 means nothing should be out of place.
    uses estimate_interference_volume, assembly_volume_actual, assembly_volume_estimate'''
    assembly_volume = assembly_volume_estimate(parts)
    estimated_interference = estimate_interference_volume(parts)
    better_estimate = assembly_volume - estimated_interference
    actual_volume = assembly_volume_actual(parts)
    difference = actual_volume - better_estimate
    if diff_diff >= threshold: return True
    else: return False
    print "estimated volume = ", estimated
    print "estimated_interference = ", estimated_interference
    print "difference = ", difference
    print "threshold = ", threshold
    if difference >= threshold:
        return True
    else:
        return False

def common_volume(part1, part2):
    '''returns the volume of the intersection of two parts'''
    shape1 = part1.shapes[0]
    shape2 = part2.shapes[0]
    common = BRepAlgoAPI_Common(shape1, shape2).Shape() #this takes too long

    tmp = GProp_GProps()
    BRepGProp().VolumeProperties(common, tmp)
    volume = tmp.Mass()
    return volume 

def part_collision(part1, part2, threshold=0.0):
    '''determines whether or not two parts are colliding, given a threshold of maximum allowable intersection
    returns True or False'''
    volume = common_volume(part1, part2)
    if volume > threshold: return True
    else: return False

def _connection_interference(self, threshold=0.0): #call this as a method please
    '''determines whether or not a connection has a geometric collision (only for the two mating parts) within a threshold
    returns True or False'''
    part1 = self.interface1.part
    part2 = self.interface2.part
    #the threshold should be the volume of interface1 + interface2 if we can isolate those regions
    return part_collision(part1, part2, threshold=threshold)
Connection.interference = _connection_interference

def _volume(self):
    '''determines the volume of the shape'''
    tmp = GProp_GProps()
    BRepGProp().VolumeProperties(self.shapes[0], tmp)
    vol = tmp.Mass()
    return vol
Part.volume = _volume

def deep_part_collider(parts):
    '''given a list of parts, checks whether or not any of them geometrically overlap
    returns a list of triples in the form: (volume, part1, part2) where volumetric interference was found'''
    errors = []
    for part in parts:
        for part2 in parts:
            volume = common_volume(part1, part2)
            if volume > 0:
               errors.append((volume, part1, part2))
    return errors