Spaces:
Sleeping
Sleeping
| from .vector import Vector, _check_vector | |
| from .frame import _check_frame | |
| from warnings import warn | |
| from sympy.utilities.misc import filldedent | |
| __all__ = ['Point'] | |
| class Point: | |
| """This object represents a point in a dynamic system. | |
| It stores the: position, velocity, and acceleration of a point. | |
| The position is a vector defined as the vector distance from a parent | |
| point to this point. | |
| Parameters | |
| ========== | |
| name : string | |
| The display name of the Point | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols | |
| >>> from sympy.physics.vector import init_vprinting | |
| >>> init_vprinting(pretty_print=False) | |
| >>> N = ReferenceFrame('N') | |
| >>> O = Point('O') | |
| >>> P = Point('P') | |
| >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3') | |
| >>> O.set_vel(N, u1 * N.x + u2 * N.y + u3 * N.z) | |
| >>> O.acc(N) | |
| u1'*N.x + u2'*N.y + u3'*N.z | |
| ``symbols()`` can be used to create multiple Points in a single step, for | |
| example: | |
| >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols | |
| >>> from sympy.physics.vector import init_vprinting | |
| >>> init_vprinting(pretty_print=False) | |
| >>> from sympy import symbols | |
| >>> N = ReferenceFrame('N') | |
| >>> u1, u2 = dynamicsymbols('u1 u2') | |
| >>> A, B = symbols('A B', cls=Point) | |
| >>> type(A) | |
| <class 'sympy.physics.vector.point.Point'> | |
| >>> A.set_vel(N, u1 * N.x + u2 * N.y) | |
| >>> B.set_vel(N, u2 * N.x + u1 * N.y) | |
| >>> A.acc(N) - B.acc(N) | |
| (u1' - u2')*N.x + (-u1' + u2')*N.y | |
| """ | |
| def __init__(self, name): | |
| """Initialization of a Point object. """ | |
| self.name = name | |
| self._pos_dict = {} | |
| self._vel_dict = {} | |
| self._acc_dict = {} | |
| self._pdlist = [self._pos_dict, self._vel_dict, self._acc_dict] | |
| def __str__(self): | |
| return self.name | |
| __repr__ = __str__ | |
| def _check_point(self, other): | |
| if not isinstance(other, Point): | |
| raise TypeError('A Point must be supplied') | |
| def _pdict_list(self, other, num): | |
| """Returns a list of points that gives the shortest path with respect | |
| to position, velocity, or acceleration from this point to the provided | |
| point. | |
| Parameters | |
| ========== | |
| other : Point | |
| A point that may be related to this point by position, velocity, or | |
| acceleration. | |
| num : integer | |
| 0 for searching the position tree, 1 for searching the velocity | |
| tree, and 2 for searching the acceleration tree. | |
| Returns | |
| ======= | |
| list of Points | |
| A sequence of points from self to other. | |
| Notes | |
| ===== | |
| It is not clear if num = 1 or num = 2 actually works because the keys | |
| to ``_vel_dict`` and ``_acc_dict`` are :class:`ReferenceFrame` objects | |
| which do not have the ``_pdlist`` attribute. | |
| """ | |
| outlist = [[self]] | |
| oldlist = [[]] | |
| while outlist != oldlist: | |
| oldlist = outlist[:] | |
| for v in outlist: | |
| templist = v[-1]._pdlist[num].keys() | |
| for v2 in templist: | |
| if not v.__contains__(v2): | |
| littletemplist = v + [v2] | |
| if not outlist.__contains__(littletemplist): | |
| outlist.append(littletemplist) | |
| for v in oldlist: | |
| if v[-1] != other: | |
| outlist.remove(v) | |
| outlist.sort(key=len) | |
| if len(outlist) != 0: | |
| return outlist[0] | |
| raise ValueError('No Connecting Path found between ' + other.name + | |
| ' and ' + self.name) | |
| def a1pt_theory(self, otherpoint, outframe, interframe): | |
| """Sets the acceleration of this point with the 1-point theory. | |
| The 1-point theory for point acceleration looks like this: | |
| ^N a^P = ^B a^P + ^N a^O + ^N alpha^B x r^OP + ^N omega^B x (^N omega^B | |
| x r^OP) + 2 ^N omega^B x ^B v^P | |
| where O is a point fixed in B, P is a point moving in B, and B is | |
| rotating in frame N. | |
| Parameters | |
| ========== | |
| otherpoint : Point | |
| The first point of the 1-point theory (O) | |
| outframe : ReferenceFrame | |
| The frame we want this point's acceleration defined in (N) | |
| fixedframe : ReferenceFrame | |
| The intermediate frame in this calculation (B) | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame | |
| >>> from sympy.physics.vector import dynamicsymbols | |
| >>> from sympy.physics.vector import init_vprinting | |
| >>> init_vprinting(pretty_print=False) | |
| >>> q = dynamicsymbols('q') | |
| >>> q2 = dynamicsymbols('q2') | |
| >>> qd = dynamicsymbols('q', 1) | |
| >>> q2d = dynamicsymbols('q2', 1) | |
| >>> N = ReferenceFrame('N') | |
| >>> B = ReferenceFrame('B') | |
| >>> B.set_ang_vel(N, 5 * B.y) | |
| >>> O = Point('O') | |
| >>> P = O.locatenew('P', q * B.x + q2 * B.y) | |
| >>> P.set_vel(B, qd * B.x + q2d * B.y) | |
| >>> O.set_vel(N, 0) | |
| >>> P.a1pt_theory(O, N, B) | |
| (-25*q + q'')*B.x + q2''*B.y - 10*q'*B.z | |
| """ | |
| _check_frame(outframe) | |
| _check_frame(interframe) | |
| self._check_point(otherpoint) | |
| dist = self.pos_from(otherpoint) | |
| v = self.vel(interframe) | |
| a1 = otherpoint.acc(outframe) | |
| a2 = self.acc(interframe) | |
| omega = interframe.ang_vel_in(outframe) | |
| alpha = interframe.ang_acc_in(outframe) | |
| self.set_acc(outframe, a2 + 2 * (omega.cross(v)) + a1 + | |
| (alpha.cross(dist)) + (omega.cross(omega.cross(dist)))) | |
| return self.acc(outframe) | |
| def a2pt_theory(self, otherpoint, outframe, fixedframe): | |
| """Sets the acceleration of this point with the 2-point theory. | |
| The 2-point theory for point acceleration looks like this: | |
| ^N a^P = ^N a^O + ^N alpha^B x r^OP + ^N omega^B x (^N omega^B x r^OP) | |
| where O and P are both points fixed in frame B, which is rotating in | |
| frame N. | |
| Parameters | |
| ========== | |
| otherpoint : Point | |
| The first point of the 2-point theory (O) | |
| outframe : ReferenceFrame | |
| The frame we want this point's acceleration defined in (N) | |
| fixedframe : ReferenceFrame | |
| The frame in which both points are fixed (B) | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols | |
| >>> from sympy.physics.vector import init_vprinting | |
| >>> init_vprinting(pretty_print=False) | |
| >>> q = dynamicsymbols('q') | |
| >>> qd = dynamicsymbols('q', 1) | |
| >>> N = ReferenceFrame('N') | |
| >>> B = N.orientnew('B', 'Axis', [q, N.z]) | |
| >>> O = Point('O') | |
| >>> P = O.locatenew('P', 10 * B.x) | |
| >>> O.set_vel(N, 5 * N.x) | |
| >>> P.a2pt_theory(O, N, B) | |
| - 10*q'**2*B.x + 10*q''*B.y | |
| """ | |
| _check_frame(outframe) | |
| _check_frame(fixedframe) | |
| self._check_point(otherpoint) | |
| dist = self.pos_from(otherpoint) | |
| a = otherpoint.acc(outframe) | |
| omega = fixedframe.ang_vel_in(outframe) | |
| alpha = fixedframe.ang_acc_in(outframe) | |
| self.set_acc(outframe, a + (alpha.cross(dist)) + | |
| (omega.cross(omega.cross(dist)))) | |
| return self.acc(outframe) | |
| def acc(self, frame): | |
| """The acceleration Vector of this Point in a ReferenceFrame. | |
| Parameters | |
| ========== | |
| frame : ReferenceFrame | |
| The frame in which the returned acceleration vector will be defined | |
| in. | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame | |
| >>> N = ReferenceFrame('N') | |
| >>> p1 = Point('p1') | |
| >>> p1.set_acc(N, 10 * N.x) | |
| >>> p1.acc(N) | |
| 10*N.x | |
| """ | |
| _check_frame(frame) | |
| if not (frame in self._acc_dict): | |
| if self.vel(frame) != 0: | |
| return (self._vel_dict[frame]).dt(frame) | |
| else: | |
| return Vector(0) | |
| return self._acc_dict[frame] | |
| def locatenew(self, name, value): | |
| """Creates a new point with a position defined from this point. | |
| Parameters | |
| ========== | |
| name : str | |
| The name for the new point | |
| value : Vector | |
| The position of the new point relative to this point | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import ReferenceFrame, Point | |
| >>> N = ReferenceFrame('N') | |
| >>> P1 = Point('P1') | |
| >>> P2 = P1.locatenew('P2', 10 * N.x) | |
| """ | |
| if not isinstance(name, str): | |
| raise TypeError('Must supply a valid name') | |
| if value == 0: | |
| value = Vector(0) | |
| value = _check_vector(value) | |
| p = Point(name) | |
| p.set_pos(self, value) | |
| self.set_pos(p, -value) | |
| return p | |
| def pos_from(self, otherpoint): | |
| """Returns a Vector distance between this Point and the other Point. | |
| Parameters | |
| ========== | |
| otherpoint : Point | |
| The otherpoint we are locating this one relative to | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame | |
| >>> N = ReferenceFrame('N') | |
| >>> p1 = Point('p1') | |
| >>> p2 = Point('p2') | |
| >>> p1.set_pos(p2, 10 * N.x) | |
| >>> p1.pos_from(p2) | |
| 10*N.x | |
| """ | |
| outvec = Vector(0) | |
| plist = self._pdict_list(otherpoint, 0) | |
| for i in range(len(plist) - 1): | |
| outvec += plist[i]._pos_dict[plist[i + 1]] | |
| return outvec | |
| def set_acc(self, frame, value): | |
| """Used to set the acceleration of this Point in a ReferenceFrame. | |
| Parameters | |
| ========== | |
| frame : ReferenceFrame | |
| The frame in which this point's acceleration is defined | |
| value : Vector | |
| The vector value of this point's acceleration in the frame | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame | |
| >>> N = ReferenceFrame('N') | |
| >>> p1 = Point('p1') | |
| >>> p1.set_acc(N, 10 * N.x) | |
| >>> p1.acc(N) | |
| 10*N.x | |
| """ | |
| if value == 0: | |
| value = Vector(0) | |
| value = _check_vector(value) | |
| _check_frame(frame) | |
| self._acc_dict.update({frame: value}) | |
| def set_pos(self, otherpoint, value): | |
| """Used to set the position of this point w.r.t. another point. | |
| Parameters | |
| ========== | |
| otherpoint : Point | |
| The other point which this point's location is defined relative to | |
| value : Vector | |
| The vector which defines the location of this point | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame | |
| >>> N = ReferenceFrame('N') | |
| >>> p1 = Point('p1') | |
| >>> p2 = Point('p2') | |
| >>> p1.set_pos(p2, 10 * N.x) | |
| >>> p1.pos_from(p2) | |
| 10*N.x | |
| """ | |
| if value == 0: | |
| value = Vector(0) | |
| value = _check_vector(value) | |
| self._check_point(otherpoint) | |
| self._pos_dict.update({otherpoint: value}) | |
| otherpoint._pos_dict.update({self: -value}) | |
| def set_vel(self, frame, value): | |
| """Sets the velocity Vector of this Point in a ReferenceFrame. | |
| Parameters | |
| ========== | |
| frame : ReferenceFrame | |
| The frame in which this point's velocity is defined | |
| value : Vector | |
| The vector value of this point's velocity in the frame | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame | |
| >>> N = ReferenceFrame('N') | |
| >>> p1 = Point('p1') | |
| >>> p1.set_vel(N, 10 * N.x) | |
| >>> p1.vel(N) | |
| 10*N.x | |
| """ | |
| if value == 0: | |
| value = Vector(0) | |
| value = _check_vector(value) | |
| _check_frame(frame) | |
| self._vel_dict.update({frame: value}) | |
| def v1pt_theory(self, otherpoint, outframe, interframe): | |
| """Sets the velocity of this point with the 1-point theory. | |
| The 1-point theory for point velocity looks like this: | |
| ^N v^P = ^B v^P + ^N v^O + ^N omega^B x r^OP | |
| where O is a point fixed in B, P is a point moving in B, and B is | |
| rotating in frame N. | |
| Parameters | |
| ========== | |
| otherpoint : Point | |
| The first point of the 1-point theory (O) | |
| outframe : ReferenceFrame | |
| The frame we want this point's velocity defined in (N) | |
| interframe : ReferenceFrame | |
| The intermediate frame in this calculation (B) | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame | |
| >>> from sympy.physics.vector import dynamicsymbols | |
| >>> from sympy.physics.vector import init_vprinting | |
| >>> init_vprinting(pretty_print=False) | |
| >>> q = dynamicsymbols('q') | |
| >>> q2 = dynamicsymbols('q2') | |
| >>> qd = dynamicsymbols('q', 1) | |
| >>> q2d = dynamicsymbols('q2', 1) | |
| >>> N = ReferenceFrame('N') | |
| >>> B = ReferenceFrame('B') | |
| >>> B.set_ang_vel(N, 5 * B.y) | |
| >>> O = Point('O') | |
| >>> P = O.locatenew('P', q * B.x + q2 * B.y) | |
| >>> P.set_vel(B, qd * B.x + q2d * B.y) | |
| >>> O.set_vel(N, 0) | |
| >>> P.v1pt_theory(O, N, B) | |
| q'*B.x + q2'*B.y - 5*q*B.z | |
| """ | |
| _check_frame(outframe) | |
| _check_frame(interframe) | |
| self._check_point(otherpoint) | |
| dist = self.pos_from(otherpoint) | |
| v1 = self.vel(interframe) | |
| v2 = otherpoint.vel(outframe) | |
| omega = interframe.ang_vel_in(outframe) | |
| self.set_vel(outframe, v1 + v2 + (omega.cross(dist))) | |
| return self.vel(outframe) | |
| def v2pt_theory(self, otherpoint, outframe, fixedframe): | |
| """Sets the velocity of this point with the 2-point theory. | |
| The 2-point theory for point velocity looks like this: | |
| ^N v^P = ^N v^O + ^N omega^B x r^OP | |
| where O and P are both points fixed in frame B, which is rotating in | |
| frame N. | |
| Parameters | |
| ========== | |
| otherpoint : Point | |
| The first point of the 2-point theory (O) | |
| outframe : ReferenceFrame | |
| The frame we want this point's velocity defined in (N) | |
| fixedframe : ReferenceFrame | |
| The frame in which both points are fixed (B) | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols | |
| >>> from sympy.physics.vector import init_vprinting | |
| >>> init_vprinting(pretty_print=False) | |
| >>> q = dynamicsymbols('q') | |
| >>> qd = dynamicsymbols('q', 1) | |
| >>> N = ReferenceFrame('N') | |
| >>> B = N.orientnew('B', 'Axis', [q, N.z]) | |
| >>> O = Point('O') | |
| >>> P = O.locatenew('P', 10 * B.x) | |
| >>> O.set_vel(N, 5 * N.x) | |
| >>> P.v2pt_theory(O, N, B) | |
| 5*N.x + 10*q'*B.y | |
| """ | |
| _check_frame(outframe) | |
| _check_frame(fixedframe) | |
| self._check_point(otherpoint) | |
| dist = self.pos_from(otherpoint) | |
| v = otherpoint.vel(outframe) | |
| omega = fixedframe.ang_vel_in(outframe) | |
| self.set_vel(outframe, v + (omega.cross(dist))) | |
| return self.vel(outframe) | |
| def vel(self, frame): | |
| """The velocity Vector of this Point in the ReferenceFrame. | |
| Parameters | |
| ========== | |
| frame : ReferenceFrame | |
| The frame in which the returned velocity vector will be defined in | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols | |
| >>> N = ReferenceFrame('N') | |
| >>> p1 = Point('p1') | |
| >>> p1.set_vel(N, 10 * N.x) | |
| >>> p1.vel(N) | |
| 10*N.x | |
| Velocities will be automatically calculated if possible, otherwise a | |
| ``ValueError`` will be returned. If it is possible to calculate | |
| multiple different velocities from the relative points, the points | |
| defined most directly relative to this point will be used. In the case | |
| of inconsistent relative positions of points, incorrect velocities may | |
| be returned. It is up to the user to define prior relative positions | |
| and velocities of points in a self-consistent way. | |
| >>> p = Point('p') | |
| >>> q = dynamicsymbols('q') | |
| >>> p.set_vel(N, 10 * N.x) | |
| >>> p2 = Point('p2') | |
| >>> p2.set_pos(p, q*N.x) | |
| >>> p2.vel(N) | |
| (Derivative(q(t), t) + 10)*N.x | |
| """ | |
| _check_frame(frame) | |
| if not (frame in self._vel_dict): | |
| valid_neighbor_found = False | |
| is_cyclic = False | |
| visited = [] | |
| queue = [self] | |
| candidate_neighbor = [] | |
| while queue: # BFS to find nearest point | |
| node = queue.pop(0) | |
| if node not in visited: | |
| visited.append(node) | |
| for neighbor, neighbor_pos in node._pos_dict.items(): | |
| if neighbor in visited: | |
| continue | |
| try: | |
| # Checks if pos vector is valid | |
| neighbor_pos.express(frame) | |
| except ValueError: | |
| continue | |
| if neighbor in queue: | |
| is_cyclic = True | |
| try: | |
| # Checks if point has its vel defined in req frame | |
| neighbor_velocity = neighbor._vel_dict[frame] | |
| except KeyError: | |
| queue.append(neighbor) | |
| continue | |
| candidate_neighbor.append(neighbor) | |
| if not valid_neighbor_found: | |
| self.set_vel(frame, self.pos_from(neighbor).dt(frame) + neighbor_velocity) | |
| valid_neighbor_found = True | |
| if is_cyclic: | |
| warn(filldedent(""" | |
| Kinematic loops are defined among the positions of points. This | |
| is likely not desired and may cause errors in your calculations. | |
| """)) | |
| if len(candidate_neighbor) > 1: | |
| warn(filldedent(f""" | |
| Velocity of {self.name} automatically calculated based on point | |
| {candidate_neighbor[0].name} but it is also possible from | |
| points(s): {str(candidate_neighbor[1:])}. Velocities from these | |
| points are not necessarily the same. This may cause errors in | |
| your calculations.""")) | |
| if valid_neighbor_found: | |
| return self._vel_dict[frame] | |
| else: | |
| raise ValueError(filldedent(f""" | |
| Velocity of point {self.name} has not been defined in | |
| ReferenceFrame {frame.name}.""")) | |
| return self._vel_dict[frame] | |
| def partial_velocity(self, frame, *gen_speeds): | |
| """Returns the partial velocities of the linear velocity vector of this | |
| point in the given frame with respect to one or more provided | |
| generalized speeds. | |
| Parameters | |
| ========== | |
| frame : ReferenceFrame | |
| The frame with which the velocity is defined in. | |
| gen_speeds : functions of time | |
| The generalized speeds. | |
| Returns | |
| ======= | |
| partial_velocities : tuple of Vector | |
| The partial velocity vectors corresponding to the provided | |
| generalized speeds. | |
| Examples | |
| ======== | |
| >>> from sympy.physics.vector import ReferenceFrame, Point | |
| >>> from sympy.physics.vector import dynamicsymbols | |
| >>> N = ReferenceFrame('N') | |
| >>> A = ReferenceFrame('A') | |
| >>> p = Point('p') | |
| >>> u1, u2 = dynamicsymbols('u1, u2') | |
| >>> p.set_vel(N, u1 * N.x + u2 * A.y) | |
| >>> p.partial_velocity(N, u1) | |
| N.x | |
| >>> p.partial_velocity(N, u1, u2) | |
| (N.x, A.y) | |
| """ | |
| from sympy.physics.vector.functions import partial_velocity | |
| vel = self.vel(frame) | |
| partials = partial_velocity([vel], gen_speeds, frame)[0] | |
| if len(partials) == 1: | |
| return partials[0] | |
| else: | |
| return tuple(partials) | |