openscvx 0.4.1.dev4__tar.gz → 0.4.1.dev11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/workflows/tests-integration.yml +1 -1
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/workflows/tests-unit.yml +1 -1
- {openscvx-0.4.1.dev4/openscvx.egg-info → openscvx-0.4.1.dev11}/PKG-INFO +3 -2
- openscvx-0.4.1.dev11/examples/drone/logo.py +440 -0
- openscvx-0.4.1.dev11/examples/drone/logo_utils/acl_logo.svg +1 -0
- openscvx-0.4.1.dev11/examples/drone/logo_utils/svg_path_utils.py +49 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/plotting_viser.py +450 -44
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/_version.py +3 -3
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/plotting/viser/animated.py +19 -7
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/plotting/viser/server.py +26 -6
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/problem.py +148 -1
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/logic.py +39 -3
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/math.py +2 -2
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11/openscvx.egg-info}/PKG-INFO +3 -2
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx.egg-info/SOURCES.txt +3 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx.egg-info/requires.txt +2 -1
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/pyproject.toml +2 -1
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/test_examples.py +9 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/assets/logo.svg +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/release-drafter.yml +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/workflows/docs.yml +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/workflows/lint.yml +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.github/workflows/release.yml +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/.gitignore +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/CONTRIBUTING.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/LICENSE +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/README.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/assets/favicon.png +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/assets/logo.svg +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/citation.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/examples.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/getting-started.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/index.md +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/arm/three_link_arm.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/car/dubins_car.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/car/dubins_car_conditional.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/car/dubins_car_stljax.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/plotting.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/figures/video_preview.png +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/1-background.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/1-background@1x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/1-background@2x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/1-background@3x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/1-background@4x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/2-mars.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/2-mars@1x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/2-mars@2x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/2-mars@3x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/2-mars@4x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/3-moon.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/3-moon@1x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/3-moon@2x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/3-moon@3x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/3-moon@4x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/4-sat1.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/4-sat1@1x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/4-sat1@2x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/4-sat1@3x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/4-sat1@4x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/5-space.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/5-space@1x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/5-space@2x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/5-space@3x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/5-space@4x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/6-earth.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/6-earth@1x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/6-earth@2x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/6-earth@3x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/images/layers/6-earth@4x.avif +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/javascripts/parallax.js +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/logo.svg +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/assets/stylesheets/parallax.css +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/home.html +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/main.html +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/partials/parallax/hero.html +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/material/overrides/partials/parallax.html +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/mkdocs.yml +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/algorithms/autotuning.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/algorithms/penalized_trust_region.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/config.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/discretization/discretization.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/expert/byof.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/expert/validation.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/init/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/solvers/base.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/time.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/utils/cache.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/utils/caching.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/utils/printing.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx/utils/utils.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/setup.cfg +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/test_autotuning.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/test_discretization.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/test_expert.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/test_init.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/test_integrators.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/test_plotting.py +0 -0
- {openscvx-0.4.1.dev4 → openscvx-0.4.1.dev11}/tests/test_propagation.py +0 -0
|
@@ -17,7 +17,7 @@ jobs:
|
|
|
17
17
|
fail-fast: false # Continue testing other examples even if one fails
|
|
18
18
|
matrix:
|
|
19
19
|
os: [ubuntu-latest, macos-latest]
|
|
20
|
-
python-version: ['3.
|
|
20
|
+
python-version: ['3.11', '3.12', '3.13']
|
|
21
21
|
|
|
22
22
|
steps:
|
|
23
23
|
- name: Checkout repository
|
|
@@ -18,7 +18,7 @@ jobs:
|
|
|
18
18
|
fail-fast: false # Continue testing other versions even if one fails
|
|
19
19
|
matrix:
|
|
20
20
|
os: [ubuntu-latest, macos-latest]
|
|
21
|
-
python-version: ['3.
|
|
21
|
+
python-version: ['3.11', '3.12', '3.13']
|
|
22
22
|
|
|
23
23
|
steps:
|
|
24
24
|
- name: Checkout repository
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 0.4.1.
|
|
3
|
+
Version: 0.4.1.dev11
|
|
4
4
|
Summary: A general Python-based successive convexification implementation which uses a JAX backend.
|
|
5
5
|
Author-email: Chris Hayner and Griffin Norris <haynec@uw.edu>
|
|
6
6
|
License: Apache Software License
|
|
@@ -10,7 +10,7 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
10
10
|
Requires-Python: >=3.9
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
|
-
Requires-Dist: cvxpy
|
|
13
|
+
Requires-Dist: cvxpy>=1.8.1
|
|
14
14
|
Requires-Dist: qoco
|
|
15
15
|
Requires-Dist: numpy
|
|
16
16
|
Requires-Dist: jax
|
|
@@ -38,6 +38,7 @@ Provides-Extra: test
|
|
|
38
38
|
Requires-Dist: pytest; extra == "test"
|
|
39
39
|
Requires-Dist: scipy; extra == "test"
|
|
40
40
|
Requires-Dist: jaxlie; extra == "test"
|
|
41
|
+
Requires-Dist: svgpathtools; extra == "test"
|
|
41
42
|
Dynamic: license-file
|
|
42
43
|
|
|
43
44
|
<a id="readme-top"></a>
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
"""6-DOF quadrotor tracing out the Autonomous Controls Laboratory Logo
|
|
2
|
+
|
|
3
|
+
This example demonstrates trajectory planning for a quadrotor tracing out the Autonomous Controls Laboratory Logo. The problem includes:
|
|
4
|
+
|
|
5
|
+
- 6-DOF rigid body dynamics (position, velocity, attitude quaternion, angular velocity)
|
|
6
|
+
- Utilizes the BYOF framework to model the angle between the boresight vector and the vector to the target.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
import jax.numpy as jnp
|
|
14
|
+
import numpy as np
|
|
15
|
+
import numpy.linalg as la
|
|
16
|
+
|
|
17
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
18
|
+
grandparent_dir = os.path.dirname(os.path.dirname(current_dir))
|
|
19
|
+
sys.path.append(grandparent_dir)
|
|
20
|
+
|
|
21
|
+
import openscvx as ox
|
|
22
|
+
from openscvx import ByofSpec, Free, Minimize, Problem
|
|
23
|
+
from examples.plotting_viser import create_animated_plotting_server
|
|
24
|
+
|
|
25
|
+
# Prompt the user to instal svgpathtools if not already installed via pip
|
|
26
|
+
try:
|
|
27
|
+
import svgpathtools
|
|
28
|
+
except ImportError:
|
|
29
|
+
print("svgpathtools not found. Please install it with: pip install svgpathtools")
|
|
30
|
+
sys.exit(1)
|
|
31
|
+
|
|
32
|
+
from examples.drone.logo_utils.svg_path_utils import get_svg_path_function
|
|
33
|
+
|
|
34
|
+
# -----------------------------------------------------------------------------
|
|
35
|
+
# SVG path utilities
|
|
36
|
+
# -----------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
# Load the SVG path function, using only Path 0 (the logo, no border)
|
|
39
|
+
svg_path_function = get_svg_path_function("examples/drone/logo_utils/acl_logo.svg", path_indices=[0])
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# -----------------------------------------------------------------------------
|
|
43
|
+
# JAX helpers (numeric versions of spatial utilities)
|
|
44
|
+
# -----------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
def qdcm(q: jnp.ndarray) -> jnp.ndarray:
|
|
47
|
+
"""Quaternion to DCM using [w, x, y, z] convention."""
|
|
48
|
+
q_norm = jnp.linalg.norm(q)
|
|
49
|
+
q_norm = jnp.where(q_norm > 1e-12, q_norm, 1e-12)
|
|
50
|
+
w, qx, qy, qz = q / q_norm
|
|
51
|
+
return jnp.array(
|
|
52
|
+
[
|
|
53
|
+
[1 - 2 * (qy**2 + qz**2), 2 * (qx * qy - qz * w), 2 * (qx * qz + qy * w)],
|
|
54
|
+
[2 * (qx * qy + qz * w), 1 - 2 * (qx**2 + qz**2), 2 * (qy * qz - qx * w)],
|
|
55
|
+
[2 * (qx * qz - qy * w), 2 * (qy * qz + qx * w), 1 - 2 * (qx**2 + qy**2)],
|
|
56
|
+
]
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def SSMP(w: jnp.ndarray) -> jnp.ndarray:
|
|
61
|
+
"""4x4 skew-symmetric matrix for quaternion dynamics."""
|
|
62
|
+
wx, wy, wz = w[0], w[1], w[2]
|
|
63
|
+
return jnp.array(
|
|
64
|
+
[
|
|
65
|
+
[0, -wx, -wy, -wz],
|
|
66
|
+
[wx, 0, wz, -wy],
|
|
67
|
+
[wy, -wz, 0, wx],
|
|
68
|
+
[wz, wy, -wx, 0],
|
|
69
|
+
]
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def SSM(w: jnp.ndarray) -> jnp.ndarray:
|
|
74
|
+
"""3x3 skew-symmetric matrix for cross products."""
|
|
75
|
+
wx, wy, wz = w[0], w[1], w[2]
|
|
76
|
+
return jnp.array([[0, -wz, wy], [wz, 0, -wx], [-wy, wx, 0]])
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# -----------------------------------------------------------------------------
|
|
80
|
+
# Problem setup
|
|
81
|
+
# -----------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
n = 500 # Number of Nodes
|
|
84
|
+
total_time = 20.0 # Total time for the simulation
|
|
85
|
+
|
|
86
|
+
# Fixed initial and final positions
|
|
87
|
+
initial_pos = np.array([-15.0, 0.0, 5.0])
|
|
88
|
+
final_pos = np.array([-14.0, -10.0, 5.0])
|
|
89
|
+
|
|
90
|
+
# State components (like other drone examples)
|
|
91
|
+
position = ox.State("position", shape=(3,))
|
|
92
|
+
position.max = np.array([20.0, 20.0, 20.0])
|
|
93
|
+
position.min = np.array([-20.0, -20.0, -5.0])
|
|
94
|
+
position.initial = [Free(initial_pos[0]), Free(initial_pos[1]), Free(initial_pos[2])]
|
|
95
|
+
position.final = [Free(final_pos[0]), Free(final_pos[1]), Free(final_pos[2])]
|
|
96
|
+
|
|
97
|
+
velocity = ox.State("velocity", shape=(3,))
|
|
98
|
+
velocity.max = np.array([20.0, 20.0, 20.0])
|
|
99
|
+
velocity.min = np.array([-20.0, -20.0, -20.0])
|
|
100
|
+
velocity.initial = [0.0, 0.0, 0.0]
|
|
101
|
+
velocity.final = [0.0, 0.0, 0.0]
|
|
102
|
+
|
|
103
|
+
attitude = ox.State("attitude", shape=(4,)) # Quaternion [w, x, y, z]
|
|
104
|
+
attitude.max = np.array([1.0, 1.0, 1.0, 1.0])
|
|
105
|
+
attitude.min = np.array([-1.0, -1.0, -1.0, -1.0])
|
|
106
|
+
attitude.initial = [Free(1.0), Free(0), Free(0), Free(0)]
|
|
107
|
+
attitude.final = [Free(1.0), Free(0), Free(0), Free(0)]
|
|
108
|
+
|
|
109
|
+
angular_velocity = ox.State("angular_velocity", shape=(3,))
|
|
110
|
+
angular_velocity.max = np.array([10.0, 10.0, 10.0])
|
|
111
|
+
angular_velocity.min = np.array([-10.0, -10.0, -10.0])
|
|
112
|
+
angular_velocity.initial = np.array([0.0, 0.0, 0.0])
|
|
113
|
+
angular_velocity.final = [Free(0), Free(0), Free(0)]
|
|
114
|
+
|
|
115
|
+
angle_metric = ox.State("angle_metric", shape=(1,)) # Viewing angle (minimize at final)
|
|
116
|
+
angle_metric.max = np.array([0.3])
|
|
117
|
+
angle_metric.min = np.array([0.0])
|
|
118
|
+
angle_metric.initial = np.array([0.0])
|
|
119
|
+
angle_metric.final = [Minimize(0.0)]
|
|
120
|
+
|
|
121
|
+
time_state = ox.Time(
|
|
122
|
+
initial=0.0,
|
|
123
|
+
final=total_time,
|
|
124
|
+
min=0.0,
|
|
125
|
+
max=total_time,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Control components
|
|
129
|
+
thrust_force = ox.Control("thrust_force", shape=(3,))
|
|
130
|
+
thrust_force.max = np.array([0.0, 0.0, 4.179446268 * 9.81])
|
|
131
|
+
thrust_force.min = np.array([0.0, 0.0, 0.0])
|
|
132
|
+
thrust_force.guess = np.repeat(np.array([[0.0, 0.0, 10.0]]), n, axis=0)
|
|
133
|
+
|
|
134
|
+
torque = ox.Control("torque", shape=(3,))
|
|
135
|
+
torque.max = np.array([10.0, 10.0, 1.0])
|
|
136
|
+
torque.min = np.array([-10.0, -10.0, -1.0])
|
|
137
|
+
torque.guess = np.zeros((n, 3))
|
|
138
|
+
|
|
139
|
+
# Offset from the SVG path for the drone to follow
|
|
140
|
+
path_offset = np.array([0.0, 0.0, 3.0]) # 3 meters above the path
|
|
141
|
+
|
|
142
|
+
# Boresight vector in body frame (x-axis of the drone)
|
|
143
|
+
boresight_body = jnp.array([1.0, 0.0, 0.0])
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def get_kp_pose(t_normalized):
|
|
147
|
+
"""
|
|
148
|
+
Get the target position along the SVG path at normalized time t, applying rotations about y and x axes.
|
|
149
|
+
Args:
|
|
150
|
+
t_normalized: Normalized time in [0, 1] (scalar or array)
|
|
151
|
+
Returns:
|
|
152
|
+
Target position [x, y, z]
|
|
153
|
+
"""
|
|
154
|
+
original_pos = jnp.array(svg_path_function(t_normalized))
|
|
155
|
+
|
|
156
|
+
scale_factor = 0.5
|
|
157
|
+
scaled_pos = original_pos * scale_factor
|
|
158
|
+
|
|
159
|
+
theta_y = jnp.pi / 2
|
|
160
|
+
cos_y = jnp.cos(theta_y)
|
|
161
|
+
sin_y = jnp.sin(theta_y)
|
|
162
|
+
R_y = jnp.array([
|
|
163
|
+
[cos_y, 0, sin_y],
|
|
164
|
+
[0, 1, 0],
|
|
165
|
+
[-sin_y, 0, cos_y]
|
|
166
|
+
])
|
|
167
|
+
|
|
168
|
+
theta_x = jnp.pi / 2
|
|
169
|
+
cos_x = jnp.cos(theta_x)
|
|
170
|
+
sin_x = jnp.sin(theta_x)
|
|
171
|
+
R_x = jnp.array([
|
|
172
|
+
[1, 0, 0],
|
|
173
|
+
[0, cos_x, -sin_x],
|
|
174
|
+
[0, sin_x, cos_x]
|
|
175
|
+
])
|
|
176
|
+
|
|
177
|
+
rotated_pos = R_x @ (R_y @ scaled_pos)
|
|
178
|
+
return rotated_pos + path_offset
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# -----------------------------------------------------------------------------
|
|
182
|
+
# BYOF: angle_metric derivative (uses get_kp_pose, not easily symbolic)
|
|
183
|
+
# -----------------------------------------------------------------------------
|
|
184
|
+
|
|
185
|
+
def angle_to_target_components(pos: jnp.ndarray, att: jnp.ndarray, t_val: float) -> jnp.ndarray:
|
|
186
|
+
"""Compute angle between boresight and vector to target from position, attitude, and time."""
|
|
187
|
+
t_normalized = t_val / total_time
|
|
188
|
+
target_pos = get_kp_pose(t_normalized)
|
|
189
|
+
|
|
190
|
+
to_target_inertial = target_pos - pos
|
|
191
|
+
boresight_inertial = qdcm(att) @ boresight_body
|
|
192
|
+
|
|
193
|
+
to_target_norm = jnp.linalg.norm(to_target_inertial)
|
|
194
|
+
boresight_norm = jnp.linalg.norm(boresight_inertial)
|
|
195
|
+
|
|
196
|
+
lhs = jnp.dot(to_target_inertial, boresight_inertial) / (to_target_norm * boresight_norm)
|
|
197
|
+
|
|
198
|
+
angle = jnp.arccos(lhs)
|
|
199
|
+
return angle
|
|
200
|
+
|
|
201
|
+
def dynamics_angle_metric(x, u, node, params):
|
|
202
|
+
"""BYOF dynamics for angle_metric: derivative = time-weighted angle to target."""
|
|
203
|
+
pos = x[position.slice]
|
|
204
|
+
att = x[attitude.slice]
|
|
205
|
+
t_val = x[time_state.slice][0]
|
|
206
|
+
angle = angle_to_target_components(pos, att, t_val)
|
|
207
|
+
return jnp.array([angle])
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
# -----------------------------------------------------------------------------
|
|
211
|
+
# Symbolic dynamics (drone: same as drone_racing / cinema_vp)
|
|
212
|
+
# -----------------------------------------------------------------------------
|
|
213
|
+
|
|
214
|
+
m = 1.0
|
|
215
|
+
g_const = -9.18
|
|
216
|
+
J_b = 1e-5 * jnp.array([1.0, 1.0, 1.0])
|
|
217
|
+
J_b_inv = 1.0 / J_b
|
|
218
|
+
J_b_diag = ox.linalg.Diag(J_b)
|
|
219
|
+
|
|
220
|
+
# Normalize quaternion for dynamics
|
|
221
|
+
q_norm = ox.linalg.Norm(attitude)
|
|
222
|
+
attitude_normalized = attitude / q_norm
|
|
223
|
+
|
|
224
|
+
dynamics = {
|
|
225
|
+
"position": velocity,
|
|
226
|
+
"velocity": (1.0 / m) * ox.spatial.QDCM(attitude_normalized) @ thrust_force
|
|
227
|
+
+ ox.Constant(np.array([0, 0, g_const], dtype=np.float64)),
|
|
228
|
+
"attitude": 0.5 * ox.spatial.SSMP(angular_velocity) @ attitude_normalized,
|
|
229
|
+
"angular_velocity": ox.linalg.Diag(J_b_inv)
|
|
230
|
+
@ (torque - ox.spatial.SSM(angular_velocity) @ J_b_diag @ angular_velocity),
|
|
231
|
+
"time": 1.0,
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
# -----------------------------------------------------------------------------
|
|
235
|
+
# Plotting patch: full_subject_traj_time for moving target
|
|
236
|
+
# -----------------------------------------------------------------------------
|
|
237
|
+
|
|
238
|
+
import examples.plotting
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def patched_full_subject_traj_time(results, params):
|
|
242
|
+
t_full = results.t_full
|
|
243
|
+
t_nodes = results.nodes["time"].flatten() if "time" in results.nodes else np.linspace(0, total_time, n)
|
|
244
|
+
|
|
245
|
+
subs_traj = []
|
|
246
|
+
subs_traj_node = []
|
|
247
|
+
subs_traj_sen = []
|
|
248
|
+
subs_traj_sen_node = []
|
|
249
|
+
|
|
250
|
+
if "moving_subject" in results.plotting_data and "get_kp_pose" in results.plotting_data:
|
|
251
|
+
custom_get_kp_pose = results.plotting_data["get_kp_pose"]
|
|
252
|
+
|
|
253
|
+
target_positions_full = []
|
|
254
|
+
target_positions_nodes = []
|
|
255
|
+
for i in range(len(t_full)):
|
|
256
|
+
t_normalized = t_full[i] / total_time
|
|
257
|
+
target_positions_full.append(np.asarray(custom_get_kp_pose(t_normalized)))
|
|
258
|
+
for i in range(len(t_nodes)):
|
|
259
|
+
t_normalized = t_nodes[i] / total_time
|
|
260
|
+
target_positions_nodes.append(np.asarray(custom_get_kp_pose(t_normalized)))
|
|
261
|
+
|
|
262
|
+
subs_traj.append(np.array(target_positions_full))
|
|
263
|
+
subs_traj_node.append(np.array(target_positions_nodes))
|
|
264
|
+
elif "init_poses" in results.plotting_data:
|
|
265
|
+
init_poses = results.plotting_data["init_poses"]
|
|
266
|
+
n_full = len(t_full)
|
|
267
|
+
n_nodes = len(t_nodes)
|
|
268
|
+
for pose in init_poses:
|
|
269
|
+
pose_full = np.repeat(pose[:, np.newaxis], n_full, axis=1).T
|
|
270
|
+
pose_node = np.repeat(pose[:, np.newaxis], n_nodes, axis=1).T
|
|
271
|
+
subs_traj.append(pose_full)
|
|
272
|
+
subs_traj_node.append(pose_node)
|
|
273
|
+
else:
|
|
274
|
+
raise ValueError("No valid method to get keypoint poses.")
|
|
275
|
+
|
|
276
|
+
subs_traj_sen = []
|
|
277
|
+
subs_traj_sen_node = []
|
|
278
|
+
return subs_traj, subs_traj_sen, subs_traj_node, subs_traj_sen_node
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
examples.plotting.full_subject_traj_time = patched_full_subject_traj_time
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def angle_to_target(x_):
|
|
285
|
+
"""Compute the angle between boresight vector and vector to target (for analysis/plotting)."""
|
|
286
|
+
pos = x_[:3]
|
|
287
|
+
att = x_[6:10]
|
|
288
|
+
t_val = x_[14]
|
|
289
|
+
return angle_to_target_components(pos, att, t_val)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
# -----------------------------------------------------------------------------
|
|
293
|
+
# States, controls, constraints, initial guess
|
|
294
|
+
# -----------------------------------------------------------------------------
|
|
295
|
+
|
|
296
|
+
states = [position, velocity, attitude, angular_velocity, angle_metric, time_state]
|
|
297
|
+
controls = [thrust_force, torque]
|
|
298
|
+
|
|
299
|
+
constraints = []
|
|
300
|
+
for state in states:
|
|
301
|
+
constraints.extend([ox.ctcs(state <= state.max), ox.ctcs(state.min <= state)])
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
byof: ByofSpec = {
|
|
305
|
+
"dynamics": {
|
|
306
|
+
"angle_metric": dynamics_angle_metric,
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
# Initial guess: position drone to maintain LoS with moving target
|
|
311
|
+
position_bar = np.linspace(initial_pos, final_pos, n)
|
|
312
|
+
velocity_bar = np.zeros((n, 3))
|
|
313
|
+
angular_velocity_bar = np.zeros((n, 3))
|
|
314
|
+
angle_metric_bar = np.zeros((n, 1))
|
|
315
|
+
time_bar = np.linspace(0, total_time, n).reshape(-1, 1)
|
|
316
|
+
|
|
317
|
+
b = np.array([1, 0, 0])
|
|
318
|
+
attitude_bar = np.tile([1.0, 0.0, 0.0, 0.0], (n, 1))
|
|
319
|
+
for k in range(n):
|
|
320
|
+
t_normalized = k / (n - 1)
|
|
321
|
+
target_pos = np.asarray(get_kp_pose(t_normalized))
|
|
322
|
+
a = target_pos - position_bar[k]
|
|
323
|
+
if np.linalg.norm(a) > 1e-6:
|
|
324
|
+
q_xyz = np.cross(b, a)
|
|
325
|
+
q_w = np.sqrt(la.norm(a) ** 2 + la.norm(b) ** 2) + np.dot(a, b)
|
|
326
|
+
q_no_norm = np.hstack((q_w, q_xyz))
|
|
327
|
+
q = q_no_norm / la.norm(q_no_norm)
|
|
328
|
+
attitude_bar[k] = q
|
|
329
|
+
|
|
330
|
+
# attitude.initial = attitude_bar[0]
|
|
331
|
+
|
|
332
|
+
position.guess = position_bar
|
|
333
|
+
velocity.guess = velocity_bar
|
|
334
|
+
attitude.guess = attitude_bar
|
|
335
|
+
angular_velocity.guess = angular_velocity_bar
|
|
336
|
+
angle_metric.guess = angle_metric_bar
|
|
337
|
+
# time_state guess is typically set by the framework; set explicitly if needed
|
|
338
|
+
time_state.guess = time_bar
|
|
339
|
+
|
|
340
|
+
# -----------------------------------------------------------------------------
|
|
341
|
+
# Problem
|
|
342
|
+
# -----------------------------------------------------------------------------
|
|
343
|
+
|
|
344
|
+
problem = Problem(
|
|
345
|
+
dynamics=dynamics,
|
|
346
|
+
states=states,
|
|
347
|
+
controls=controls,
|
|
348
|
+
time=time_state,
|
|
349
|
+
constraints=constraints,
|
|
350
|
+
N=n,
|
|
351
|
+
byof=byof,
|
|
352
|
+
time_dilation_factor_min=0.001,
|
|
353
|
+
time_dilation_factor_max=3.0,
|
|
354
|
+
autotuner=ox.RampProximalWeight(),
|
|
355
|
+
float_dtype="float64",
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
# problem.settings.scp.ep_tr = 1.6e-3
|
|
359
|
+
problem.settings.scp.autotuner.ramp_factor = 1.06
|
|
360
|
+
problem.settings.scp.autotuner.lam_prox_max = 1e3
|
|
361
|
+
|
|
362
|
+
problem.settings.scp.lam_vc = 1e3
|
|
363
|
+
problem.settings.scp.lam_cost = 6e0
|
|
364
|
+
problem.settings.cvx.solver_args = {"canon_backend": "COO", "enforce_dpp": True}
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
plotting_dict = {
|
|
368
|
+
"svg_path_function": svg_path_function,
|
|
369
|
+
"path_offset": path_offset,
|
|
370
|
+
"total_time": total_time,
|
|
371
|
+
"initial_pos": initial_pos,
|
|
372
|
+
"final_pos": final_pos,
|
|
373
|
+
"boresight_body": boresight_body,
|
|
374
|
+
"moving_subject": True,
|
|
375
|
+
"get_kp_pose": get_kp_pose,
|
|
376
|
+
"angle_to_target": angle_to_target,
|
|
377
|
+
"extend_boresight": True,
|
|
378
|
+
"relative_vector": True,
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if __name__ == "__main__":
|
|
382
|
+
problem.initialize()
|
|
383
|
+
results = problem.solve()
|
|
384
|
+
results = problem.post_process()
|
|
385
|
+
|
|
386
|
+
results.update_plotting_data(**plotting_dict)
|
|
387
|
+
|
|
388
|
+
# Define the plane the logo actually lies in (from three points on the logo)
|
|
389
|
+
p0 = np.asarray(get_kp_pose(0.0))
|
|
390
|
+
p1 = np.asarray(get_kp_pose(0.33))
|
|
391
|
+
p2 = np.asarray(get_kp_pose(0.67))
|
|
392
|
+
v1 = p1 - p0
|
|
393
|
+
v2 = p2 - p0
|
|
394
|
+
plane_normal = np.cross(v1, v2)
|
|
395
|
+
nrm = np.linalg.norm(plane_normal)
|
|
396
|
+
if nrm < 1e-10:
|
|
397
|
+
plane_normal = np.array([1.0, 0.0, 0.0]) # fallback
|
|
398
|
+
else:
|
|
399
|
+
plane_normal = plane_normal / nrm
|
|
400
|
+
plane_point = p0
|
|
401
|
+
|
|
402
|
+
def ray_plane_intersection(ray_origin, ray_direction, p_plane, n_plane):
|
|
403
|
+
denom = np.dot(ray_direction, n_plane)
|
|
404
|
+
if abs(denom) < 1e-10:
|
|
405
|
+
return None
|
|
406
|
+
t = np.dot(p_plane - ray_origin, n_plane) / denom
|
|
407
|
+
if t < 0:
|
|
408
|
+
return None
|
|
409
|
+
return ray_origin + t * ray_direction
|
|
410
|
+
|
|
411
|
+
pos_traj = np.asarray(results.trajectory["position"])
|
|
412
|
+
tt = np.asarray(results.trajectory["time"]).reshape(-1)
|
|
413
|
+
total_time_f = float(total_time)
|
|
414
|
+
target_traj = np.stack(
|
|
415
|
+
[np.asarray(get_kp_pose(float(t) / total_time_f)) for t in tt],
|
|
416
|
+
axis=0,
|
|
417
|
+
)
|
|
418
|
+
traced_path = []
|
|
419
|
+
for i in range(len(pos_traj)):
|
|
420
|
+
rel = target_traj[i] - pos_traj[i]
|
|
421
|
+
nrm = np.linalg.norm(rel)
|
|
422
|
+
rel_dir = rel / nrm
|
|
423
|
+
pt = ray_plane_intersection(pos_traj[i], rel_dir, plane_point, plane_normal)
|
|
424
|
+
traced_path.append(pt if pt is not None else target_traj[i])
|
|
425
|
+
results["traced_path_on_plane"] = np.array(traced_path, dtype=np.float64)
|
|
426
|
+
results["logo_plane_point"] = plane_point
|
|
427
|
+
results["logo_plane_normal"] = plane_normal
|
|
428
|
+
|
|
429
|
+
from openscvx.plotting import plot_states, plot_controls, plot_virtual_control_heatmap, plot_trust_region_heatmap
|
|
430
|
+
plot_states(results).show()
|
|
431
|
+
plot_controls(results).show()
|
|
432
|
+
plot_virtual_control_heatmap(results).show()
|
|
433
|
+
plot_trust_region_heatmap(results).show()
|
|
434
|
+
|
|
435
|
+
server = create_animated_plotting_server(
|
|
436
|
+
results,
|
|
437
|
+
thrust_key="thrust_force",
|
|
438
|
+
show_grid=True,
|
|
439
|
+
)
|
|
440
|
+
server.sleep_forever()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg width="2677" height="1585" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" overflow="hidden"><defs><clipPath id="clip0"><rect x="861" y="55" width="2677" height="1585"/></clipPath><clipPath id="clip1"><rect x="861" y="55" width="2677" height="1585"/></clipPath></defs><g clip-path="url(#clip0)" transform="translate(-861 -55)"><g clip-path="url(#clip1)"><path d="M1241.55 59.0003 1264.22 59.5552C1592.31 75.6573 1859.59 322.995 1906.33 641.936L1907.45 653.344 1929.38 632.908C1945.48 618.885 1962.1 605.359 1979.2 592.376 2081.06 515.049 2262.42 453.475 2425.92 474.972 2591.85 496.79 2668.15 670.343 2502.8 846.804 2438.38 915.551 2404.12 930.752 2346.19 967.571 2328.7 975.467 2311.2 987.945 2307.46 960.328L2339.06 881.296C2369.29 844.685 2428.99 834.397 2488.83 740.664 2572.4 609.772 2503.13 559.768 2367.17 553.844 2246.18 548.572 2131.6 582.52 2005.85 670.926 1757.83 845.292 1675.63 1128.42 1741.75 1361.31 1794.22 1546.17 2082.48 1720.61 2555.24 1315.28 2567.16 1305.51 2575.66 1298.86 2582.43 1295.07L2591.32 1291.58 2551.48 1266.51C2544.07 1261.85 2541.84 1252.06 2546.51 1244.66L2584.48 1184.39 2576.78 1179.55 2567.63 1194.08C2563.95 1199.92 2557.24 1202.7 2550.82 1201.65L2544.79 1199.36 2544.78 1199.39 2378.12 1094.52 2369.99 1056.08 2381.99 1053.7 2383.11 1059 2419.87 1000.65 2373.16 1012 2378.57 1037.56 2366.57 1039.94 2362.77 1021.96 2362.95 1021.68 2362.49 1020.65 2362.38 1020.11 2362.17 1013.44C2362.55 1011.11 2363.4 1008.82 2364.73 1006.69 2366.07 1004.57 2367.78 1002.81 2369.72 1001.46L2375.82 998.77 2376.36 998.638 2377.49 998.603 2377.64 998.368 2377.62 998.332 2449.76 980.803 2449.76 980.802 2616.27 1085.59C2622.12 1089.27 2624.89 1095.97 2623.85 1102.38L2621.8 1107.78 2630.24 1094.38 2630.38 1094.47 2612.81 1122.35 2619.54 1126.59 2642.65 1089.91 2633.89 1078.93C2623.34 1060.99 2618.72 1043.56 2621.45 1029.01L2623.11 1024.71 2662.44 1046.36 2662.64 1050.45C2669.6 1066.36 2694.41 1090.07 2727.59 1110.95 2771.83 1138.79 2814.18 1151.05 2822.19 1138.34 2828.2 1128.81 2813.18 1107.93 2786.63 1086.35L2769.98 1074.47 2755.7 1097.14C2754.09 1099.7 2750.71 1100.47 2748.15 1098.86L2729.62 1087.2C2727.06 1085.59 2726.29 1082.21 2727.9 1079.65L2742.19 1056.98 2724.27 1047.11C2706.86 1038.9 2691.23 1033.88 2679.82 1032.75L2672.21 1032.9 2631.29 1010.38 2635.12 1006.11C2658.51 987.345 2706.5 990.997 2755.54 1015.07L2765.19 1020.46 2788.59 983.321 2786.42 978.399C2784.74 971.032 2785.88 963.026 2790.23 956.127 2796.74 945.78 2808.63 940.863 2819.99 942.716 2823.78 943.334 2827.51 944.704 2830.96 946.876 2844.76 955.563 2848.91 973.79 2840.21 987.586 2835.87 994.485 2829.14 998.969 2821.77 1000.64L2816.38 1000.81 2792.99 1037.95 2802.02 1044.32C2851.07 1082.94 2875.45 1131.86 2857.31 1160.66 2846.93 1177.13 2824.64 1183.91 2796.97 1181.56L2783.29 1178.41 2760.18 1215.09 2766.91 1219.33 2775.78 1205.24 2775.84 1205.28 2780.16 1200.75C2783.71 1198.27 2788.12 1197.27 2792.4 1197.97L2797.89 1200.06 2797.97 1199.93 2965.1 1305.1 2980.37 1377.27 2979.85 1377.34 2979.7 1377.58 2980.25 1378.84 2980.09 1379.72 3002.34 1379.72 3002.34 509.89C3002.34 499.812 3010.51 491.642 3020.6 491.642L3093.63 491.642C3103.71 491.642 3111.88 499.812 3111.88 509.89L3111.88 1400.68 3159.91 1400.68 3159.91 1418.1 3138.07 1418.1 3160.39 1436.3 3115.45 1455.46 3160.39 1474.74 3137.74 1493.32 3219.59 1493.32 3209.72 1478.69C3206.73 1471.63 3205.08 1463.86 3205.08 1455.71 3205.08 1447.56 3206.73 1439.79 3209.72 1432.73L3219.59 1418.1 3176.41 1418.1 3176.41 1400.68 3185.55 1400.68 3150.93 1325.54 3149.42 1318.07C3149.42 1310 3154.33 1303.08 3161.33 1300.12L3167.63 1298.85 3242.33 1299.51 3244.57 1298.59 3246.9 1299.55 3252.71 1299.61 3257.75 1304.05 3258.35 1304.29 3258.82 1304.99 3367.41 1400.68 3471.69 1400.68C3474.21 1400.68 3476.61 1401.19 3478.79 1402.11L3479.36 1402.5 3479.36 1401.59 3531.75 1443.25 3531.74 1444.66 3532.56 1445C3535.3 1447.74 3537 1451.53 3537 1455.71 3537 1459.89 3535.3 1463.68 3532.56 1466.42L3531.58 1466.83 3531.58 1467.74 3479.36 1509.26 3479.36 1508.35 3478.79 1508.73C3476.61 1509.66 3474.21 1510.17 3471.69 1510.17L3365.99 1510.17 3258.79 1604.38 3258.35 1605.03 3257.78 1605.26 3252.71 1609.72 3246.89 1609.77 3244.57 1610.74 3242.34 1609.81 3167.63 1610.48 3161.33 1609.2C3154.33 1606.25 3149.42 1599.32 3149.42 1591.25L3150.9 1583.92 3151.16 1583.36 3151.35 1583.08 3151.32 1583.02 3184.97 1510.17 3095.07 1510.17 3093.63 1510.76 3020.6 1510.76C3010.51 1510.76 3002.34 1502.59 3002.34 1492.52L3002.34 1491.92 3002.34 1418.93 3002.34 1396.21 2974.89 1396.21 2974.89 1394.64 2966.53 1400.61 2965.16 1400.66 2964.61 1401.53 2956.86 1403.41 2955.11 1391.26 2970.06 1387.62 2960.11 1340.62 2923.35 1398.97 2939 1395.17 2940.75 1407.32 2893.46 1418.82 2893.46 1418.82 2726.33 1313.65 2726.41 1313.52 2722.15 1309.47C2718.44 1304.14 2718.04 1296.89 2721.72 1291.05L2730.87 1276.52 2723.18 1271.68 2685.21 1331.94C2680.55 1339.35 2670.76 1341.57 2663.34 1336.91L2620.13 1309.71 2622.43 1316.82C2622.3 1322.01 2620.35 1328.2 2615.66 1335.56 2596.9 1364.99 2569.36 1403.68 2486.74 1468.61 2096.43 1779.1 1753.84 1602.75 1686.08 1446.94 1588.14 1221.71 1648.07 970.487 1799.6 771.311L1832.58 730.938 1832.21 729.155 1832.21 729.155 1831.74 710.8C1816.11 402.635 1568.64 155.603 1260.18 140.464L1246.95 140.14 1246.95 198.467 1257.27 198.719C1535.85 212.391 1759.35 435.491 1773.46 713.802L1773.88 730.123 1773.09 733.993C1771.78 737.094 1769.3 739.579 1766.19 740.89L1761.77 741.782 1705.31 741.782 1700.8 740.89C1697.7 739.59 1695.2 737.114 1693.88 734.018L1692.87 729.155 1692.8 729.077 1692.51 717.97C1680.5 481.124 1490.3 291.263 1253.23 279.628L1246.95 279.475 1246.95 338.211 1270.24 339.349C1468.07 358.799 1624.07 520.657 1634.23 720.972L1634.51 731.935 1634.09 733.993C1632.78 737.094 1630.3 739.579 1627.19 740.891L1622.78 741.781 1563.34 741.781 1561.05 741.33C1557.95 740.029 1555.45 737.554 1554.13 734.457L1553.13 729.595 1553.09 729.557 1552.04 708.718C1536.5 555.841 1414.42 434.444 1261.18 419.866L1246.95 419.193 1246.95 477.938 1284.64 481.498C1399.46 503.486 1488.21 598.815 1500.2 716.824 1499.4 976.483 1504.25 1358.34 1501.58 1490.11 1501.58 1499.7 1493.8 1507.48 1484.21 1507.48L1414.71 1507.48C1405.11 1507.48 1397.34 1499.7 1397.34 1490.11L1397.34 1229.61 1070.62 1229.61 1070.62 1490.83C1070.62 1500.42 1062.84 1508.19 1053.25 1508.19L983.749 1508.19C974.153 1508.19 966.373 1500.42 966.373 1490.83L966.373 1229.61 879.156 1229.61 877.461 1229.09 877.092 1228.52 867.833 1224.69 867.225 1223.95 863 1213.76 864.748 1209.54 864.191 1208.68 908.799 1133.91 909.757 1133.47 911.023 1130.42C913.784 1127.66 917.597 1125.95 921.81 1125.95L922.502 1126.24 922.624 1125.7 1070.77 1125.7 1070.77 1126.09 1399.58 1126.09 1399.58 744.828 1399.19 744.828C1399.19 654.187 1325.67 580.708 1234.98 580.708 1144.29 580.708 1070.77 654.187 1070.77 744.828L1070.77 954.745 1070.62 954.623 1070.62 1109.2 966.428 1109.2 967.755 716.824C979.746 598.815 1068.5 503.486 1183.32 481.498L1230.45 477.045 1230.45 406.668 1230.3 405.943 1230.14 405.787 1230.14 350.054 1230.45 348.51 1230.45 267.384 1230.3 266.659 1230.14 266.503 1230.14 210.768 1230.45 209.226 1230.45 128.277 1230.3 127.554 1230.14 127.397 1230.14 71.2757 1231.06 66.6685C1232.36 63.5624 1234.83 61.0685 1237.93 59.745Z" fill="#000000" fill-rule="evenodd" fill-opacity="1"/></g></g></svg>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import jax.numpy as jnp
|
|
3
|
+
from svgpathtools import svg2paths, svg2paths2
|
|
4
|
+
|
|
5
|
+
def print_svg_path_attributes(svg_file_path):
|
|
6
|
+
"""
|
|
7
|
+
Print the attributes of all paths in the SVG file for inspection.
|
|
8
|
+
"""
|
|
9
|
+
paths, attributes, svg_attr = svg2paths2(svg_file_path)
|
|
10
|
+
for i, attr in enumerate(attributes):
|
|
11
|
+
print(f"Path {i}: {attr}")
|
|
12
|
+
|
|
13
|
+
def extract_svg_path(svg_file_path, n_points=2000, flip_y=True, path_indices=None):
|
|
14
|
+
"""
|
|
15
|
+
Extract a continuous, high-resolution path from an SVG file using svgpathtools.
|
|
16
|
+
Optionally, only use specific path indices.
|
|
17
|
+
"""
|
|
18
|
+
paths, attributes, svg_attr = svg2paths2(svg_file_path)
|
|
19
|
+
if path_indices is not None:
|
|
20
|
+
paths = [paths[i] for i in path_indices]
|
|
21
|
+
all_points = []
|
|
22
|
+
for path in paths:
|
|
23
|
+
for seg in path:
|
|
24
|
+
seg_len = seg.length()
|
|
25
|
+
n_seg_points = max(2, int(n_points * seg_len / path.length()))
|
|
26
|
+
ts = np.linspace(0, 1, n_seg_points, endpoint=False)
|
|
27
|
+
for t in ts:
|
|
28
|
+
pt = seg.point(t)
|
|
29
|
+
all_points.append([pt.real, pt.imag])
|
|
30
|
+
all_points = np.array(all_points)
|
|
31
|
+
min_x, max_x = np.min(all_points[:, 0]), np.max(all_points[:, 0])
|
|
32
|
+
min_y, max_y = np.min(all_points[:, 1]), np.max(all_points[:, 1])
|
|
33
|
+
if flip_y:
|
|
34
|
+
all_points[:, 1] = max_y - (all_points[:, 1] - min_y)
|
|
35
|
+
all_points[:, 0] = 20 * (all_points[:, 0] - min_x) / (max_x - min_x) - 10
|
|
36
|
+
all_points[:, 1] = 20 * (all_points[:, 1] - min_y) / (max_y - min_y) - 10
|
|
37
|
+
all_points = np.column_stack([all_points, np.full(len(all_points), 2.0)])
|
|
38
|
+
idxs = np.linspace(0, len(all_points) - 1, n_points).astype(int)
|
|
39
|
+
sampled_points = all_points[idxs]
|
|
40
|
+
# Convert to JAX array for JAX-compatible indexing
|
|
41
|
+
sampled_points_jax = jnp.array(sampled_points)
|
|
42
|
+
def path_function(t):
|
|
43
|
+
t = jnp.clip(t, 0, 1)
|
|
44
|
+
idx = jnp.clip(jnp.floor(t * (n_points - 1)), 0, n_points - 1).astype(int)
|
|
45
|
+
return sampled_points_jax[idx]
|
|
46
|
+
return path_function
|
|
47
|
+
|
|
48
|
+
def get_svg_path_function(svg_file_path, path_indices=None):
|
|
49
|
+
return extract_svg_path(svg_file_path, n_points=2000, flip_y=True, path_indices=path_indices)
|