def computeMagnitude(point, sphereCenter): magnitudeSquared = c3d.magnitudeSquared(point) magnitude = math.sqrt(magnitudeSquared) direction = c3d.multiplyByScalar(point, 1 / magnitude) magnitudeSquared = max(1.0, magnitudeSquared) magnitude = max(1.0, magnitude) cosAlpha = np.dot(direction, sphereCenter) sinAlpha = c3d.magnitude(np.cross(direction, sphereCenter)) cosBeta = 1.0 / magnitude sinBeta = math.sqrt(magnitudeSquared - 1.0) * cosBeta return 1.0 / (cosAlpha * cosBeta - sinAlpha * sinBeta)
def fromPoints(points, boundingSphere): if len(points) < 1: raise Exception('Your list of points must contain at least 2 points') # Bring coordinates to ellipsoid scaled coordinates scaleDown = lambda coord: [coord[0] * rX, coord[1] * rY, coord[2] * rZ] scaledPoints = map(scaleDown, points) scaledSphereCenter = scaleDown(boundingSphere.center) magnitude = lambda coord: computeMagnitude(coord, scaledSphereCenter) magnitudes = map(magnitude, scaledPoints) return c3d.multiplyByScalar(scaledSphereCenter, max(magnitudes))
def fromPoints(self, points): if len(points) < 1: raise Exception('Your list of points must contain at least 2 points') nbPositions = len(points) for i in xrange(0, nbPositions): point = points[i] # Store the points containing the smallest and largest component # Used for the naive approach if point[0] < self.minPointX[0]: self.minPointX = point if point[1] < self.minPointY[1]: self.minPointY = point if point[2] < self.minPointZ[2]: self.minPointZ = point if point[0] > self.maxPointX[0]: self.maxPointX = point if point[1] > self.maxPointY[1]: self.maxPointY = point if point[2] > self.maxPointZ[2]: self.maxPointZ = point # Squared distance between each component min and max xSpan = c3d.magnitudeSquared(c3d.subtract(self.maxPointX, self.minPointX)) ySpan = c3d.magnitudeSquared(c3d.subtract(self.maxPointY, self.minPointY)) zSpan = c3d.magnitudeSquared(c3d.subtract(self.maxPointZ, self.minPointZ)) diameter1 = self.minPointX diameter2 = self.maxPointX maxSpan = xSpan if ySpan > maxSpan: maxSpan = ySpan diameter1 = self.minPointY diameter2 = self.maxPointY if zSpan > maxSpan: maxSpan = zSpan diameter1 = self.minPointZ diameter2 = self.maxPointZ ritterCenter = [ (diameter1[0] + diameter2[0]) * 0.5, (diameter1[1] + diameter2[1]) * 0.5, (diameter1[2] + diameter2[2]) * 0.5 ] radiusSquared = c3d.magnitudeSquared(c3d.subtract(diameter2, ritterCenter)) ritterRadius = math.sqrt(radiusSquared) # Initial center and radius (naive) get min and max box minBoxPt = [self.minPointX[0], self.minPointY[1], self.minPointZ[2]] maxBoxPt = [self.maxPointX[0], self.maxPointY[1], self.maxPointZ[2]] naiveCenter = c3d.multiplyByScalar(c3d.add(minBoxPt, maxBoxPt), 0.5) naiveRadius = 0.0 for i in xrange(0, nbPositions): currentP = points[i] # Find the furthest point from the naive center to calculate the naive radius. r = c3d.magnitude(c3d.subtract(currentP, naiveCenter)) if r > naiveRadius: naiveRadius = r # Make adjustments to the Ritter Sphere to include all points. oldCenterToPointSquared = c3d.magnitudeSquared(c3d.subtract(currentP, ritterCenter)) if oldCenterToPointSquared > radiusSquared: oldCenterToPoint = math.sqrt(oldCenterToPointSquared) ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5 # Calculate center of new Ritter sphere oldToNew = oldCenterToPoint - ritterRadius ritterCenter = [ (ritterRadius * ritterCenter[0] + oldToNew * currentP[0]) / oldCenterToPoint, (ritterRadius * ritterCenter[1] + oldToNew * currentP[1]) / oldCenterToPoint, (ritterRadius * ritterCenter[2] + oldToNew * currentP[2]) / oldCenterToPoint, ] # Keep the naive sphere if smaller if naiveRadius < ritterRadius: self.radius = ritterRadius self.center = ritterCenter else: self.radius = naiveRadius self.center = naiveCenter
def fromPoints(self, points): if len(points) < 1: raise Exception( 'Your list of points must contain at least 2 points') nbPositions = len(points) for i in xrange(0, nbPositions): point = points[i] # Store the points containing the smallest and largest component # Used for the naive approach if point[0] < self.minPointX[0]: self.minPointX = point if point[1] < self.minPointY[1]: self.minPointY = point if point[2] < self.minPointZ[2]: self.minPointZ = point if point[0] > self.maxPointX[0]: self.maxPointX = point if point[1] > self.maxPointY[1]: self.maxPointY = point if point[2] > self.maxPointZ[2]: self.maxPointZ = point # Squared distance between each component min and max xSpan = c3d.magnitudeSquared( c3d.subtract(self.maxPointX, self.minPointX)) ySpan = c3d.magnitudeSquared( c3d.subtract(self.maxPointY, self.minPointY)) zSpan = c3d.magnitudeSquared( c3d.subtract(self.maxPointZ, self.minPointZ)) diameter1 = self.minPointX diameter2 = self.maxPointX maxSpan = xSpan if ySpan > maxSpan: maxSpan = ySpan diameter1 = self.minPointY diameter2 = self.maxPointY if zSpan > maxSpan: maxSpan = zSpan diameter1 = self.minPointZ diameter2 = self.maxPointZ ritterCenter = [(diameter1[0] + diameter2[0]) * 0.5, (diameter1[1] + diameter2[1]) * 0.5, (diameter1[2] + diameter2[2]) * 0.5] radiusSquared = c3d.magnitudeSquared( c3d.subtract(diameter2, ritterCenter)) ritterRadius = math.sqrt(radiusSquared) # Initial center and radius (naive) get min and max box minBoxPt = [self.minPointX[0], self.minPointY[1], self.minPointZ[2]] maxBoxPt = [self.maxPointX[0], self.maxPointY[1], self.maxPointZ[2]] naiveCenter = c3d.multiplyByScalar(c3d.add(minBoxPt, maxBoxPt), 0.5) naiveRadius = 0.0 for i in xrange(0, nbPositions): currentP = points[i] # Find the furthest point from the naive center to calculate the naive radius. r = c3d.magnitude(c3d.subtract(currentP, naiveCenter)) if r > naiveRadius: naiveRadius = r # Make adjustments to the Ritter Sphere to include all points. oldCenterToPointSquared = c3d.magnitudeSquared( c3d.subtract(currentP, ritterCenter)) if oldCenterToPointSquared > radiusSquared: oldCenterToPoint = math.sqrt(oldCenterToPointSquared) ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5 # Calculate center of new Ritter sphere oldToNew = oldCenterToPoint - ritterRadius ritterCenter = [ (ritterRadius * ritterCenter[0] + oldToNew * currentP[0]) / oldCenterToPoint, (ritterRadius * ritterCenter[1] + oldToNew * currentP[1]) / oldCenterToPoint, (ritterRadius * ritterCenter[2] + oldToNew * currentP[2]) / oldCenterToPoint ] # Keep the naive sphere if smaller if naiveRadius < ritterRadius: self.radius = ritterRadius self.center = ritterCenter else: self.radius = naiveRadius self.center = naiveCenter