---
title: "3D Plotting"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{3D Plotting}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.width = 7,
fig.height = 5
)
```
```{r}
library(orbitr)
```
All simulations in `orbitr` run in full 3D — every body always has `x`, `y`, and `z` coordinates. When all motion happens in the XY plane (i.e., `z = 0` and `vz = 0` for every body), `plot_orbits()` produces a static 2D `ggplot2` chart. The moment any body has non-zero Z motion, `plot_orbits()` automatically switches to an interactive 3D `plotly` visualization — no code changes needed.
You can also force 3D rendering for planar data with `three_d = TRUE`, which can be useful if you want the interactive rotation and zoom capabilities even for a flat system.
## How the 2D/3D Dispatch Works
`plot_orbits()` checks whether `any(sim_data$z != 0)`. If there's any Z-axis movement — or if you pass `three_d = TRUE` — it hands off to `plot_orbits_3d()`, which uses `plotly` for interactive 3D rendering. Otherwise it falls back to a static `ggplot2` chart.
If `plotly` isn't installed, the function warns you and falls back to the 2D plot even for 3D data.
## A Tilted Lunar Orbit
The Moon's real orbit is inclined about 5° to the ecliptic. You can approximate this by giving the Moon a small `vz` component:
```{r}
create_system() |>
add_body("Earth", mass = mass_earth) |>
add_body("Moon", mass = mass_moon,
x = distance_earth_moon,
vy = speed_moon * cos(5 * pi / 180),
vz = speed_moon * sin(5 * pi / 180)) |>
simulate_system(time_step = seconds_per_hour, duration = seconds_per_day * 28) |>
plot_orbits()
```
Because `vz` is non-zero, `plot_orbits()` detects 3D motion and returns an interactive plotly widget. You can drag to rotate, scroll to zoom, and hover to see timestamps.
## Forcing 3D for Flat Data
Even if your system is entirely planar, you can opt into the interactive 3D viewer:
```{r}
create_system() |>
add_body("Earth", mass = mass_earth) |>
add_body("Moon", mass = mass_moon, x = distance_earth_moon, vy = speed_moon) |>
simulate_system(time_step = seconds_per_hour, duration = seconds_per_day * 28) |>
plot_orbits(three_d = TRUE)
```
This gives you the same rotation and zoom controls, even though all the Z values are zero.