Skip to content

Commit 0e675eb

Browse files
chore: release v0.4.0
1 parent e2b42a8 commit 0e675eb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+5357
-1174
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ __pycache__/
33
.mypy_cache/
44
.pytest_cache/
55
.ruff_cache/
6-
.pdm-python
76
.python-version
8-
.egg-info/
7+
*.egg-info/
8+
.venv
99

1010
docs/source/index.md
1111
docs/source/api_reference

README.md

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929

3030
## 🚀 快速开始
3131

32-
> 以下示例使用了 Python 项目管理工具:[PDM](https://pdm-project.org/)
32+
> 以下示例使用了 Python 项目管理工具:[UV](https://docs.astral.sh/uv/)
3333
>
34-
> 在开始之前,请先[安装](https://pdm-project.org/en/latest/#installation)该工具。
34+
> 在开始之前,请先[安装](https://docs.astral.sh/uv/getting-started/installation/)该工具。
3535
3636
### 1. 克隆仓库:
3737

@@ -43,23 +43,17 @@ cd motrixsim-docs
4343
git lfs pull
4444
```
4545

46-
### 2. 创建虚拟环境
47-
48-
```bash
49-
pdm use 3.10
50-
```
51-
52-
### 3. 安装依赖
46+
### 2. 安装依赖
5347

5448
```
5549
# 检查更新并安装依赖
56-
pdm install -G examples -v
50+
uv sync --extra examples --upgrade
5751
5852
# 不检查更新,直接安装依赖
59-
pdm sync -G examples -v
53+
uv sync --extra examples
6054
```
6155

62-
### 4. 执行对比与示例
56+
### 3. 执行对比与示例
6357

6458
> 参考 [文档](https://motrixsim.readthedocs.io) 中的说明
6559

docs/CLAUDE.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ This is the documentation project for MotrixSim, a high-performance physics simu
5656
- sphinx-design (design components)
5757
- sphinx_copybutton (code copy functionality)
5858
- **Language Support**: Chinese (zh_CN) and English with automatic content copying
59-
- **Autodoc**: Automatic API documentation generation from Python docstrings
59+
- **Autodoc**: Automatic API documentation generation
6060

6161
### Dependencies
6262
Documentation dependencies are managed in the parent `pyproject.toml`:
@@ -82,6 +82,15 @@ docs = [
8282
- **Code Examples**: Include practical code examples with proper syntax highlighting
8383
- **API Documentation**: Use NumPy/Google style docstrings for autodoc generation
8484

85+
### Important: Document Structure
86+
**Critical**: The documentation has a specific structure that must be followed:
87+
88+
- **`source/user_guide/`**: This directory is **auto-generated** during build. **DO NOT** edit files here directly.
89+
- **`source/zh_CN/`**: This directory contains the **manually written** Chinese documentation. All edits should be made here.
90+
- **`source/en/`**: This directory contains the **manually written** English documentation.
91+
92+
The build system automatically copies content from language-specific directories (`zh_CN/`, `en/`) to the main structure during compilation. Always edit the source files in the appropriate language directory, not the auto-generated files.
93+
8594
### Media and Assets
8695
- **Videos**: Embedded using sphinxcontrib-video extension
8796
- **Images**: Stored in `_static/images/` with poster images for videos
@@ -113,12 +122,6 @@ docs = [
113122
3. Verify multilingual content works correctly
114123
4. Test all embedded media and interactive elements
115124

116-
## File Naming Conventions
117-
- Use lowercase with underscores for file names
118-
- Index files should be named `index.md`
119-
- API documentation files should match module names
120-
- Media files should be descriptive and use appropriate extensions
121-
122125
## Integration Notes
123126
- This documentation project is part of the larger motrixsim-py package
124127
- The build system automatically detects and documents the motrixsim package

docs/source/en/user_guide/getting_started/mjcf.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ MJCF contains a rich set of tags and attributes. This section lists the current
2828
- **Planned Attributes**
2929
- **Unsupported Attributes**
3030
* - option
31-
- timestep, gravity, iterations, tolerance
32-
- apirate, wind, magnetic, density, viscosity, o_margin, o_solref, o_solimp, o_friction, actuatorgroupdisable
31+
- timestep, gravity, iterations, tolerance, o_margin, o_solref, o_solimp, o_friction
32+
- apirate, wind, magnetic, density, viscosity, actuatorgroupdisable
3333
- impratio, integrator, cone, jacobian, solver, ls_iterations, ls_tolerance, noslip_iterations, noslip_tolerance, ccd_iterations, ccd_tolerance, sdf_iterations, sdf_initpoints
3434
* - compiler
3535
- autolimits, angle, eulerseq, meshdir, texturedir, assetdir

docs/source/en/user_guide/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ main_function/render
3030

3131
```{toctree}
3232
:caption: Kinematics
33-
:maxdepth: 1
33+
:maxdepth: 2
3434
kinematics/body
3535
kinematics/floating_base
3636
kinematics/joint

docs/source/en/user_guide/kinematics/geometry.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Once you obtain a Geom object, you can read information such as its position, or
3030
You can run a simple example of Geom API usage with:
3131

3232
```bash
33-
pdm run examples/geom.py
33+
uv run examples/geom.py
3434
```
3535

3636
See the source code at [`examples/geom.py`](../../../../examples/geom.py)
@@ -39,3 +39,9 @@ See the source code at [`examples/geom.py`](../../../../examples/geom.py)。
3939
[`model.geoms`]: motrixsim.SceneModel.geoms
4040
[`model.get_geom(key)`]: motrixsim.SceneModel.get_geom
4141
[`Geom API`]: motrixsim.Geom
42+
43+
```{toctree}
44+
:maxdepth: 1
45+
geometry/hfield
46+
47+
```
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
# Height Fields (HField)
2+
3+
Height Fields (HField) are an efficient geometry type for representing terrain surfaces. They store elevation information through 2D grid data, providing realistic physical collision responses for robot simulation, terrain following, and surface interaction.
4+
5+
## Height Field Features
6+
7+
Height fields offer the following advantages:
8+
9+
- **Efficient Storage**: Uses regular grids to store elevation data with low memory footprint
10+
- **Fast Collision Detection**: Grid-based spatial partitioning algorithms provide efficient collision queries
11+
- **Realistic Terrain Simulation**: Supports complex terrain features such as hillsides, ravines, plains, etc.
12+
- **Large-scale Scenes**: Suitable for representing large terrain areas, commonly used in outdoor robot simulation
13+
14+
## MJCF Configuration
15+
16+
In MJCF files, height fields are defined using the `<hfield>` tag, supporting three data source methods:
17+
18+
### 1. Inline Elevation Data
19+
20+
Directly specify elevation data matrix in XML:
21+
22+
```xml
23+
<asset>
24+
<hfield name="terrain1"
25+
nrow="15"
26+
ncol="15"
27+
elevation="0.0 0.43 0.78 0.97 ..."
28+
size="5 5 2 0.1"/>
29+
</asset>
30+
```
31+
32+
### 2. PNG Image Files
33+
34+
Use PNG images as elevation data source (recommended for visual terrain):
35+
36+
```xml
37+
<asset>
38+
<hfield name="png_terrain"
39+
file="terrain.png"
40+
content_type="image/png"
41+
size="10 10 3 0.2"/>
42+
</asset>
43+
```
44+
45+
**Notes:**
46+
47+
- PNG images are automatically converted to grayscale
48+
- White pixels correspond to high elevation, black pixels to low elevation
49+
- Intensity values are used as elevation data and normalized to [0, 1] range
50+
51+
### 3. Custom Binary Files
52+
53+
Use MuJoCo custom binary format:
54+
55+
```xml
56+
<asset>
57+
<hfield name="binary_terrain"
58+
file="terrain.hfield"
59+
content_type="image/vnd.mujoco.hfield"
60+
size="8 8 2.5 0.15"/>
61+
</asset>
62+
```
63+
64+
**Binary file format:**
65+
66+
- File size: `4 × (2 + nrow × ncol)` bytes
67+
- Structure:
68+
- `int32 nrow`: Number of rows
69+
- `int32 ncol`: Number of columns
70+
- `float32 data[nrow×ncol]`: Elevation data (row-major order)
71+
72+
### MJCF Attribute Description
73+
74+
| Attribute | Type | Default | Description |
75+
| -------------- | ------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
76+
| `name` | string | optional | Height field name for reference. If omitted and file name is specified, uses filename (without path and extension) |
77+
| `content_type` | string | optional | **Currently ignored by MotrixSim** |
78+
| `file` | string | optional | External file path. `.png` files are converted to grayscale, intensity values used as elevation data; other formats treated as custom binary format |
79+
| `nrow` | integer | "0" | Number of rows in elevation data matrix. Default 0 means load from file and automatically infer matrix size |
80+
| `ncol` | integer | "0" | Number of columns in elevation data matrix |
81+
| `elevation` | float array (nrow×ncol) | optional | Inline elevation data matrix. Data automatically normalized to [0, 1] range. Defaults to 0 if not provided |
82+
| `size` | float array (4 elements) | required | Physical dimensions: `[radius_x, radius_y, elevation_z, base_z]` |
83+
84+
### Detailed size Attribute Description
85+
86+
The `size` attribute contains four floats: `[radius_x, radius_y, elevation_z, base_z]`, with each parameter meaning:
87+
88+
- **radius_x**: Radius in X direction (half-width). Total width of height field on X axis is `2 × radius_x`
89+
- **radius_y**: Radius in Y direction (half-length). Total length of height field on Y axis is `2 × radius_y`
90+
- **elevation_z**: Maximum elevation. This value scales normalized [0-1] elevation data, so lowest point is at Z=0, highest point at Z=elevation_z
91+
- **base_z**: Base depth. **Currently ignored by MotrixSim**
92+
93+
**Important Notes:**
94+
95+
- Height fields are centered in the local coordinate system of the referencing geometry
96+
- Elevation direction is +Z direction
97+
- Unlike planes, height fields are treated as unions of regular geometry, with no concept of "below height field" - geometry is either inside or outside the height field
98+
- Therefore, base parts must have non-zero thickness to avoid penetration issues
99+
100+
**Example:**
101+
102+
```xml
103+
<!-- Create a 10×10 unit height field with max elevation 2 units and base thickness 0.1 units -->
104+
<hfield name="terrain" size="5 5 2 0.1" nrow="50" ncol="50"/>
105+
```
106+
107+
### Collision Detection Features
108+
109+
Height field collision detection has the following important characteristics:
110+
111+
**Collision Model:**
112+
113+
- Height fields are treated as unions of triangular prisms
114+
- First select potentially colliding sub-grid prisms based on geometry bounding boxes
115+
- Then use general convex colliders for precise collision calculation
116+
117+
**Supported Collision Types:**
118+
119+
- ✅ Height field with sphere, capsule, cylinder, cube, polyhedron
120+
- ❌ Height field with plane collision (not supported)
121+
- ❌ Height field with other height field collision (not supported)
122+
123+
For more detailed hfield field descriptions, please refer to the [MJCF official documentation](https://mujoco.readthedocs.io/en/3.3.7/XMLreference.html#asset-hfield).
124+
125+
### Geometry Reference
126+
127+
Use height fields in `<worldbody>`:
128+
129+
```xml
130+
<worldbody>
131+
<geom name="terrain" type="hfield" hfield="terrain1" material="ground_material"/>
132+
<geom pos="10 0 0" name="terrain2" type="hfield" hfield="file_terrain" material="ground_material"/>
133+
</worldbody>
134+
```
135+
136+
## Main Interfaces
137+
138+
In MotrixSim, you can access HField objects through the following methods:
139+
140+
- [`model.num_hfields`]: Get the number of height fields in the current scene.
141+
- [`model.get_hfield(name_or_index)`]: Get a specific height field object by name or index.
142+
143+
### HField Object Properties
144+
145+
After obtaining an HField object, you can access the following properties:
146+
147+
```python
148+
hfield = model.get_hfield("terrain1")
149+
150+
# Basic properties
151+
name = hfield.name # Height field name
152+
nrow = hfield.nrow # Number of grid rows
153+
ncol = hfield.ncol # Number of grid columns
154+
bound = hfield.bound # Bounding box [-x, -y, 0, x, y, z]
155+
156+
# Elevation data
157+
height_matrix = hfield.height_matrix # Complete elevation matrix (nrow × ncol)
158+
159+
# Query elevation at specific point
160+
height = hfield.get(row=5, col=10) # Get elevation at specified row and column
161+
```
162+
163+
## Usage Examples
164+
165+
### Basic Height Field Operations
166+
167+
```{literalinclude} ../../../../../examples/hfield.py
168+
:language: python
169+
:dedent:
170+
:start-after: "# tag::basic_access"
171+
:end-before: "# end::basic_access"
172+
```
173+
174+
### Elevation Data Analysis
175+
176+
```{literalinclude} ../../../../../examples/hfield.py
177+
:language: python
178+
:dedent:
179+
:start-after: "# tag::height_analysis"
180+
:end-before: "# end::height_analysis"
181+
```
182+
183+
### Complete Simulation Example
184+
185+
```{literalinclude} ../../../../../examples/hfield.py
186+
:language: python
187+
:dedent:
188+
```
189+
190+
Run the height field simulation example:
191+
192+
```bash
193+
uv run examples/hfield.py
194+
```
195+
196+
## File Format
197+
198+
MotrixSim supports binary height field file format (`.hfield`):
199+
200+
### File Structure
201+
202+
- **Header**: First 8 bytes
203+
- `nrow` (int32): Number of grid rows
204+
- `ncol` (int32): Number of grid columns
205+
- **Data section**: Remaining bytes
206+
- Elevation data array (float32), length `nrow × ncol`
207+
208+
### Generating Height Field Files
209+
210+
You can create custom height field files using the following method:
211+
212+
```python
213+
import numpy as np
214+
215+
def create_hfield_file(filename, height_data):
216+
"""Create binary height field file"""
217+
nrow, ncol = height_data.shape
218+
219+
with open(filename, 'wb') as f:
220+
# Write header information
221+
f.write(np.array([nrow, ncol], dtype=np.int32).tobytes())
222+
# Write elevation data
223+
f.write(height_data.astype(np.float32).tobytes())
224+
225+
# Example: Create simple terrain
226+
x = np.linspace(-5, 5, 50)
227+
y = np.linspace(-5, 5, 50)
228+
X, Y = np.meshgrid(x, y)
229+
Z = 0.5 * np.sin(X) * np.cos(Y) # Sine wave terrain
230+
231+
create_hfield_file("custom_terrain.hfield", Z)
232+
```
233+
234+
## API Reference
235+
236+
For more HField-related APIs, please refer to:
237+
238+
- [`HField API`]: Complete height field class interface documentation
239+
- [`SceneModel.get_hfield()`]: Method to get height field objects
240+
- [`SceneModel.num_hfields`]: Get number of height fields
241+
242+
[`model.num_hfields`]: motrixsim.SceneModel.num_hfields
243+
[`model.get_hfield(name_or_index)`]: motrixsim.SceneModel.get_hfield
244+
[`HField API`]: motrixsim.HField
245+
[`SceneModel.get_hfield()`]: motrixsim.SceneModel.get_hfield
246+
[`SceneModel.num_hfields`]: motrixsim.SceneModel.num_hfields

docs/source/en/user_guide/kinematics/link.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Once you have a Link object, you can manipulate it using a variety of properties
2929
You can run a simple example demonstrating link API usage with:
3030

3131
```bash
32-
pdm run examples/link.py
32+
uv run examples/link.py
3333
```
3434

3535
See the source code at [`examples/link.py`](../../../../examples/link.py).

0 commit comments

Comments
 (0)