def intersecPerpendicularLine(A, B, C, info=0): """ Return the intersection between the Line L defined by A and B and the Line perpendicular crossing the point C. """ if A == B: return None ax, ay, az = A.x, A.y, A.z bx, by, bz = B.x, B.y, B.z cx, cy, cz = C.x, C.y, C.z ux, uy, uz = bx - ax, by - ay, bz - az if (ux * ux + uy * uy + uz * uz) == 0.0: return None k = (ux * cx + uy * cy + uz * cz - ux * ax - uy * ay - uz * az) / (ux * ux + uy * uy + uz * uz) tx = ax + k * ux ty = ay + k * uy tz = az + k * uz T = Vector(tx, ty, tz) vx, vy, vz = tx - cx, ty - cy, tz - cz V = Vector(vx, vy, vz) distance = math.sqrt(V.dot(V)) # Tprime = T + V if info == 1: msgCsl("Intersection Point at distance of " + str(distance) + " is : " + format(T)) return T #, distance, Tprime
def intersecLinePlane(A, B, plane): """ Return the intersection between a line A,B and a planar face. """ N = plane.normalAt(0, 0) a, b, c = N.x, N.y, N.z p1 = plane.CenterOfMass d = -((a * p1.x) + (b * p1.y) + (c * p1.z)) ax, ay, az = A.x, A.y, A.z bx, by, bz = B.x, B.y, B.z ux, uy, uz = bx - ax, by - ay, bz - az U = Vector(ux, uy, uz) if U.dot(N) == 0.0: # if A belongs to P : the full Line L is included in the Plane if (a * ax) + (b * ay) + (c * az) + d == 0.0: return A # if not the Plane and line are paralell without intersection else: return None else: if (a * ux + b * uy + c * uz) == 0.0: return None k = -1 * (a * ax + b * ay + c * az + d) / (a * ux + b * uy + c * uz) tx = ax + k * ux ty = ay + k * uy tz = az + k * uz T = Vector(tx, ty, tz) return T
def projectPoint(self, p, direction=None, force_projection=True): """Project a point onto the plane, by default orthogonally. Parameters ---------- p : Base::Vector3 The point to project. direction : Base::Vector3, optional The unit vector that indicates the direction of projection. It defaults to `None`, which then uses the `plane.axis` (normal) value, meaning that the point is projected perpendicularly to the plane. force_projection: Bool, optional Forces the projection if the deviation between the direction and the normal is less than float epsilon from the orthogonality. The direction of projection is modified to a float epsilon deviation between the direction and the orthogonal. It defaults to True. Returns ------- Base::Vector3 The projected vector, scaled to the appropriate distance. """ axis = Vector(self.axis).normalize() if direction is None: dir = axis else: dir = Vector(direction).normalize() cos = dir.dot(axis) delta_ax_proj = (p - self.position).dot(axis) # check the only conflicting case: direction orthogonal to axis if abs(cos) <= float_info.epsilon: if force_projection: cos = math.copysign(float_info.epsilon, delta_ax_proj) dir = axis.cross(dir).cross(axis) - cos * axis else: return None proj = p - delta_ax_proj / cos * dir return proj
def get_spherical_coords(x, y, z): """Get the Spherical coordinates of the vector represented by Cartesian coordinates (x, y, z). Parameters ---------- vector : Base::Vector3 The input vector. Returns ------- tuple of float Tuple (radius, theta, phi) with the Spherical coordinates. Radius is the radial coordinate, theta the polar angle and phi the azimuthal angle in radians. Notes ----- The vector (0, 0, 0) has undefined values for theta and phi, while points on the z axis has undefined value for phi. The following conventions are used (useful in DraftToolBar methods): (0, 0, 0) -> (0, pi/2, 0) (0, 0, z) -> (radius, theta, 0) """ v = Vector(x, y, z) x_axis = Vector(1, 0, 0) z_axis = Vector(0, 0, 1) y_axis = Vector(0, 1, 0) rad = v.Length if not bool(round(rad, precision())): return (0, math.pi / 2, 0) theta = v.getAngle(z_axis) v.projectToPlane(Vector(0, 0, 0), z_axis) phi = v.getAngle(x_axis) if math.isnan(phi): return (rad, theta, 0) # projected vector is on 3rd or 4th quadrant if v.dot(Vector(y_axis)) < 0: phi = -1 * phi return (rad, theta, phi)