125 lines
5.4 KiB
Diff
125 lines
5.4 KiB
Diff
Based on my knowledge of the SymPy codebase and the issue description, I can provide the patch. The issue is that `Point.vel()` should automatically calculate velocity from position information if velocity hasn't been explicitly defined, similar to how `ReferenceFrame.ang_vel_in()` works.
|
|
|
|
The key insight from the issue:
|
|
1. When you call `Q.set_pos(P, r)` to set position of Q relative to P as vector `r`
|
|
2. Then `Q.vel(A)` should calculate velocity by taking the time derivative of `r` in frame A (i.e., `r.dt(A)`)
|
|
3. This mirrors how `ang_vel_in()` calculates angular velocity from orientation
|
|
|
|
Here's the patch that implements this fix:
|
|
|
|
--- a/sympy/physics/vector/point.py
|
|
+++ b/sympy/physics/vector/point.py
|
|
@@ -1,6 +1,7 @@
|
|
from __future__ import print_function, division
|
|
from .vector import Vector, _check_vector
|
|
from .frame import _check_frame
|
|
+from warnings import warn
|
|
|
|
__all__ = ['Point']
|
|
|
|
@@ -515,9 +516,56 @@ class Point(object):
|
|
Examples
|
|
========
|
|
|
|
- >>> from sympy.physics.vector import Point, ReferenceFrame
|
|
+ >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
|
|
>>> N = ReferenceFrame('N')
|
|
>>> p1 = Point('p1')
|
|
- >>> p1.set_vel(N, 10 * N.x)
|
|
+ >>> p2 = Point('p2')
|
|
+ >>> q = dynamicsymbols('q')
|
|
+ >>> p1.set_vel(N, 10 * N.x)
|
|
+ >>> p2.set_pos(p1, q * N.y)
|
|
>>> p1.vel(N)
|
|
10*N.x
|
|
+ >>> p2.vel(N)
|
|
+ q'*N.y
|
|
|
|
"""
|
|
|
|
_check_frame(frame)
|
|
- if not (frame in self._vel_dict):
|
|
- raise ValueError('Velocity of point ' + self.name + ' has not been'
|
|
- ' defined in ReferenceFrame ' + frame.name)
|
|
- return self._vel_dict[frame]
|
|
+ if frame in self._vel_dict:
|
|
+ return self._vel_dict[frame]
|
|
+ else:
|
|
+ # Try to calculate velocity from position information
|
|
+ visited = set()
|
|
+ queue = [self]
|
|
+ while queue:
|
|
+ node = queue.pop(0)
|
|
+ if node in visited:
|
|
+ continue
|
|
+ visited.add(node)
|
|
+ # Check if node has velocity defined in frame
|
|
+ if frame in node._vel_dict:
|
|
+ # Calculate velocity by going backwards through position tree
|
|
+ path = self._pdict_path(node)
|
|
+ if path is not None:
|
|
+ vel = node._vel_dict[frame]
|
|
+ for i in range(len(path) - 1, 0, -1):
|
|
+ # Get position of path[i-1] from path[i]
|
|
+ pos_vec = path[i-1].pos_from(path[i])
|
|
+ # Velocity contribution from this position vector
|
|
+ vel = vel + pos_vec.dt(frame)
|
|
+ return vel
|
|
+ # Add neighbors (points with position defined relative to node)
|
|
+ for other_point in node._pos_dict.keys():
|
|
+ if other_point not in visited:
|
|
+ queue.append(other_point)
|
|
+ raise ValueError('Velocity of point ' + self.name + ' has not been'
|
|
+ ' defined in ReferenceFrame ' + frame.name)
|
|
+
|
|
+ def _pdict_path(self, other):
|
|
+ """Returns a list of points that connect self to other.
|
|
+
|
|
+ The list will start with self and end with other.
|
|
+ Returns None if no path exists.
|
|
+ """
|
|
+ # BFS to find path from self to other via _pos_dict
|
|
+ from collections import deque
|
|
+ queue = deque([(self, [self])])
|
|
+ visited = {self}
|
|
+ while queue:
|
|
+ node, path = queue.popleft()
|
|
+ if node == other:
|
|
+ return path
|
|
+ for neighbor in node._pos_dict.keys():
|
|
+ if neighbor not in visited:
|
|
+ visited.add(neighbor)
|
|
+ queue.append((neighbor, path + [neighbor]))
|
|
+ return None
|
|
|
|
Wait, let me reconsider. Looking at the actual SymPy codebase structure more carefully based on the issue and hints, the fix should be simpler and follow the pattern used in `ang_vel_in()`. Let me provide a cleaner patch:
|
|
|
|
--- a/sympy/physics/vector/point.py
|
|
+++ b/sympy/physics/vector/point.py
|
|
@@ -519,8 +519,26 @@ class Point(object):
|
|
"""
|
|
|
|
_check_frame(frame)
|
|
- if not (frame in self._vel_dict):
|
|
- raise ValueError('Velocity of point ' + self.name + ' has not been'
|
|
- ' defined in ReferenceFrame ' + frame.name)
|
|
- return self._vel_dict[frame]
|
|
+ if frame in self._vel_dict:
|
|
+ return self._vel_dict[frame]
|
|
+ else:
|
|
+ # Try to calculate velocity from position information
|
|
+ # by finding a point with known velocity and using the
|
|
+ # time derivative of the position vector
|
|
+ visited = []
|
|
+ queue = [self]
|
|
+ while queue:
|
|
+ node = queue.pop(0)
|
|
+ if node not in visited:
|
|
+ visited.append(node)
|
|
+ if frame in node._vel_dict:
|
|
+ return node._vel_dict[frame] + self.pos_from(node).dt(frame)
|
|
+ for neighbor in node._pos_dict:
|
|
+ if neighbor not in visited:
|
|
+ queue.append(neighbor)
|
|
+ raise ValueError('Velocity of point ' + self.name + ' has not been'
|
|
+ ' defined in ReferenceFrame ' + frame.name)
|