def add_intermediate_point(self): """If last and first points are not the same we need to compute an intermediate point location.""" """The point is used to close the polygon.""" coordBegin = OSMCoord.coordDictionnary[self.ref[0]] coordEnd = OSMCoord.coordDictionnary[self.ref[-1]] distance = length2D(coordBegin.x - coordEnd.x, coordBegin.z - coordEnd.z) angle = math.atan2(coordBegin.z - coordEnd.z, coordBegin.x - coordEnd.x) # there is two possible 'optimal' intermediate points # we select the one that is the farthest from all the other coord (=>inside the lake) x1 = math.cos(math.pi / 2 + angle) * (distance / 2) + (coordBegin.x + coordEnd.x) / 2 z1 = math.sin(math.pi / 2 + angle) * (distance / 2) + (coordBegin.z + coordEnd.z) / 2 x2 = -math.cos(math.pi / 2 + angle) * (distance / 2) + (coordBegin.x + coordEnd.x) / 2 z2 = -math.sin(math.pi / 2 + angle) * (distance / 2) + (coordBegin.z + coordEnd.z) / 2 distanceSum1 = OSMMultipolygon.sum_distances_to_coords( OSMCoord.coordDictionnary, x1, z1, 2000) distanceSum2 = OSMMultipolygon.sum_distances_to_coords( OSMCoord.coordDictionnary, x2, z2, 2000) if distanceSum1 < distanceSum2: x = x1 z = z1 else: x = x2 z = z2 self.ref.append(OSMCoord.add_new_coord_to_list(x, z))
def sum_distances_to_coords(coordlist, x, z, threshold): """Return the sum of the distances to each point closer than the threshold.""" total = 0 for index in coordlist: distance = length2D(coordlist[index].x - x, coordlist[index].z - z) if distance <= threshold: total = total + distance return total
def length(self): """Return the length of a barrier.""" length = 0 for index in range(len(self.ref)): if index > 0: x = OSMCoord.coordDictionnary[self.ref[index]].x - OSMCoord.coordDictionnary[self.ref[index - 1]].x z = OSMCoord.coordDictionnary[self.ref[index]].z - OSMCoord.coordDictionnary[self.ref[index - 1]].z length = length + length2D(x, z) return length
def get_tilt(self, p1, p2): """Return tilt at p1 in direction of p2.""" x1 = p1['x'] - p2['x'] z1 = p1['z'] - p2['z'] x2 = -z1 z2 = x1 len = length2D(x2, z2) if len == 0: return 0 x2 = x2 / len z2 = z2 / len h1 = self.interpolate_height(p1['x'], p2['z']) h2 = self.interpolate_height(p1['x'] + x2, p2['z'] + z2) return math.atan2(h1 - h2, 1)
def interpolate_height(self, X, Z): """Interpolate the height at a given position.""" xMinus = -float('inf') zMinus = -float('inf') xPlus = float('inf') zPlus = float('inf') heights = [0, 0, 0, 0] # get the 'boundary' box: # zMinus # 0---1 # xMinus | c | xPlus # 3---2 # zPlus distance = [] for elevation in self.elevationArray: currentX = elevation['x'] currentZ = elevation['z'] distance.append(length2D(X - currentX, Z - currentZ)) if currentX < X: if currentX > xMinus: xMinus = currentX else: if currentX < xPlus: xPlus = currentX if currentZ < Z: if currentZ > zMinus: zMinus = currentZ else: if currentZ < zPlus: zPlus = currentZ for elevation in self.elevationArray: if elevation['x'] == xMinus and elevation['z'] == zMinus: heights[0] = elevation['height'] elif elevation['x'] == xMinus and elevation['z'] == zPlus: heights[3] = elevation['height'] elif elevation['x'] == xPlus and elevation['z'] == zMinus: heights[1] = elevation['height'] elif elevation['x'] == xPlus and elevation['z'] == zPlus: heights[2] = elevation['height'] # compute the ration to determine in which of the two triangle of the box the point lies ratio1 = (zPlus - zMinus) / (xPlus - xMinus) ratio2 = (Z - zMinus) / (X - xMinus) # use a barycentric coordinate system in order to interpolate the value in the triangle # http://en.wikipedia.org/wiki/Barycentric_coordinate_system x1 = xMinus z1 = zMinus if ratio2 < ratio1: # use triangle 0-1-2 x2 = xPlus x3 = xPlus z2 = zMinus z3 = zPlus else: # use triangle 0-2-3 x2 = xPlus x3 = xMinus z2 = zPlus z3 = zPlus denominator = (z2 - z3) * (x1 - x3) + (x3 - x2) * (z1 - z3) lambda1 = ((z2 - z3) * (X - x3) + (x3 - x2) * (Z - z3)) / denominator lambda2 = ((z3 - z1) * (X - x3) + (x1 - x3) * (Z - z3)) / denominator lambda3 = 1 - lambda1 - lambda2 if ratio2 < ratio1: height = lambda1 * heights[0] + lambda2 * heights[ 1] + lambda3 * heights[2] else: height = lambda1 * heights[0] + lambda2 * heights[ 2] + lambda3 * heights[3] if math.isnan(height) or height == float( 'inf') or height == -float('inf'): return 0 else: return height