---
title: "Shooting reconstruction with explicit uncertainty"
output:
  rmarkdown::html_vignette:
    toc: true
vignette: >
  %\VignetteIndexEntry{Shooting reconstruction with explicit uncertainty}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 6,
                      dpi = 96, out.width = "100%")
# on Linux the default X11 png device cannot draw semi-transparent fills; use cairo there
if (Sys.info()[["sysname"]] == "Linux" && isTRUE(capabilities("cairo"))) knitr::opts_chunk$set(dev.args = list(png = list(type = "cairo")))
library(forensicR)
set.seed(2026)
```

Shooting incident reconstruction answers a narrow question with geometry:
given the defects a bullet left, where could it have come from? forensicR
follows the standard field workflow (Haag & Haag, *Shooting Incident
Reconstruction*; Hueske, *Practical Analysis and Reconstruction of Shooting
Incidents*; OSAC 2025-N-0003 terminology) and adds the one thing paper
cannot: every result carries the uncertainty of the measurements it came
from.

Throughout, the frame is x east, y north, z up; azimuths are degrees
clockwise from north; a trajectory's direction is the direction of
**flight**, and its **anchor** is the defect where the bullet struck.

## 1. Impact angle from a defect

A bullet striking a flat, non-yielding surface leaves an elliptical defect.
The angle of impact relative to the surface is approximately
`asin(width / length)`. Measure both axes and give the measurement error:

```{r impact}
impact_angle(width = c(9.1, 6.0), length = c(9.3, 12.5), se = 0.5)
```

Two things to notice. Near 90 degrees (a nearly round defect) the interval
is wide: the ellipse simply does not carry much information there. And the
method is only valid on surfaces that do not deform: drywall, wood, sheet
metal. Not glass, not fabric.

## 2. Three ways to establish a trajectory

### Rod or laser angles at the defect

The most common method. Record the vertical angle (angle finder) and the
horizontal angle (protractor or total station), both as the direction of
flight. Five degrees is a commonly cited uncertainty for rods; use what
your validation supports.

```{r rod}
t_rod <- trajectory_from_angles(anchor = c(2.0, 5.0, 1.35),
                                azimuth_deg = 352, vertical_deg = -3,
                                se_azimuth = 5, se_vertical = 5, id = "D2 rod")
t_rod
```

### Two points on the path

Entry and exit of a wall, a defect and a probe tip, two defects in line.
Positional uncertainty is propagated to the angles. The trajectory is
anchored at the second point (the impact); the first is kept and becomes
the joint of a segmented path (section 6).

```{r twopt}
t_2pt <- trajectory_2pt(p1 = c(3.4, 4.2, 1.20), p2 = c(3.73, 4.92, 1.10),
                        se_position = 0.01, id = "D3 two-point")
t_2pt
```

### A single defect's ellipse plus directionality

When no rod can be placed. Needs the ellipse, the orientation of its major
axis on the wall (0 = vertical, 90 = horizontal, clockwise as seen from
the shooter's side) and which end the bullet came from (lead-in mark,
pinch point). The wall's facing direction fixes the frame.

```{r ellipse}
t_ell <- trajectory_from_defect(anchor = c(1.2, 5.0, 1.60), width = 9.3, length = 10.0,
                                major_axis_deg = 85, wall_azimuth_deg = 180,
                                came_from = "right", se = 0.5, se_orientation = 5,
                                id = "D1 ellipse")
t_ell
trajs <- list(t_rod, t_2pt, t_ell)
trajectory_table(trajs)[, c("id", "method", "azimuth_deg", "se_azimuth", "vertical_deg", "se_vertical")]
```

Compare the uncertainties: the two-point method with centimeter positions
is ten times tighter than the rod; the ellipse of a nearly round defect is
the loosest. The plots below show the same thing as fans.

## 3. Seeing the cone, not the line

```{r plan}
walls <- rbind(room_rect(0, 0, 6, 5), opening(2.5, 0, 3.5, 0, "door"))
plot_trajectories(trajs, view = "plan", walls = walls, back = 6, convergence = TRUE)
```

```{r elev, fig.height = 3.4}
plot_trajectories(trajs, view = "elevation", back = 6)
```

The dashed lines in the elevation view are assumed muzzle heights. Where
the fan crosses them is where a shooter of that posture could have been.

## 4. Where was the shooter?

`origin_zone()` intersects the back-projected line with each assumed
height and reports the horizontal distance and position, with Monte Carlo
intervals. `max_distance` bounds the search to the scene; `furniture`
excludes positions inside objects.

```{r origin}
origin_zone(t_rod, heights = c(standing = 1.5, kneeling = 1.0, prone = 0.3),
            max_distance = 12)
```

`p_reachable` is the fraction of draws that reach that height within the
distance limit. A low value means the height is poorly supported by the
trajectory, and the interval is conditional on the draws that do reach it.
Report both numbers.

## 5. Several shots: do they converge?

If two shots came from one position, their back-projected lines should
pass close to each other *behind* both defects. `intersect_trajectories()`
gives the closest approach, the miss distance and whether it lies behind
both defects, all with Monte Carlo spread.

```{r converge}
ix <- intersect_trajectories(t_rod, t_2pt)
ix$point
ix$miss_distance
ix$behind_both
ix$summary
```

In this example the three defects were simulated from one shooter standing
at (2.4, 2.0, 1.5) and the reconstruction recovers that point to a few
centimeters. A small miss distance is consistent with, but does not prove,
a single firing position.

## 6. Objects on the path

With the scene's furniture, `trajectory_obstructions()` reports which
objects each back-projected line passes through and between which
distances. A hit means the object is an intermediate target (look for a
defect in it) or the path must be reconsidered.

```{r obstructions}
furn <- rbind(along_wall(walls, "north", from = 3.4, length = 2.1, depth = 0.9, id = "Sofa", type = "sofa"),
              furniture("Floor lamp", "box", x = 1.95, y = 3.85, width = 0.3, depth = 0.3, height = 1.7))
trajectory_obstructions(trajs, furn, back = 6)
```

## 7. Segmented paths through intermediate targets

A bullet that passes through a table, a door or a wardrobe follows two or
more straight segments. Each segment is measured on its own; the path
orders them from the shooter's side to the terminal defect and records the
joints (exit points).

```{r path}
seg_in  <- trajectory_from_angles(anchor = c(4.0, 2.6, 0.5), azimuth_deg = 69, vertical_deg = -30,
                                  id = "D4 into table")
seg_out <- trajectory_2pt(p1 = c(4.25, 3.1, 0.45), p2 = c(4.9, 5.0, 0.2), se_position = 0.01,
                          id = "D4 to wall")
shot4 <- trajectory_path(seg_in, seg_out, id = "Shot 4")
shot4
path_deflections(shot4)[, c("joint", "deflection_deg", "lower", "upper", "miss_in", "miss_out", "joint_source")]
```

The deflection is the angle between the measured segments, with its
interval. `miss_in` and `miss_out` are the distances from the joint to
each segment's line: if either is larger than your measurement uncertainty
allows, the documented segments do not actually meet at that joint.

**Deflection is never predicted.** How much a bullet deviates when it
passes through something depends on the bullet, its velocity, the material
and the angle, and cannot be computed reliably from the scene. When the
path after an object was not documented, `assumed_segment()` continues the
incoming direction with a cone whose width *you* state. It is flagged
`ASSUMED` in every table and plot, drawn dashed, and refused by
`origin_zone()`.

```{r assumed}
shot5 <- trajectory_path(seg_in,
                         assumed_segment(seg_in, joint = c(4.25, 3.1, 0.45), length = 2.5,
                                         se_deflection = 10, id = "after table (assumed)"),
                         id = "Shot 5")
trajectory_table(shot5)[, c("id", "path", "segment", "assumed", "method")]
plot_trajectories(list(shot4, shot5), view = "plan", walls = walls,
                  furniture = furniture("Coffee table", "table", x = 3.9, y = 2.6, width = 1.0, depth = 0.5),
                  back = 4)
```

For origin analysis and convergence, only the first segment of a path
(the one on the shooter's side) is used.

## 8. In three dimensions

```{r fig3d, echo = FALSE, fig.cap = "The three trajectories of section 2 rendered to scale: rods with arrowheads at the defects, wireframe cones for the angular uncertainty, floor grid with numbered axes."}
knitr::include_graphics("figures/shooting-dollhouse.png")
```

```{r render, eval = FALSE}
render_scene_3d(walls, NULL, trajs, file = "shooting.png", view = "dollhouse")
```

## 9. What to write in the report

- The **method** for each trajectory and the **uncertainty you assigned**
  to it, with the reason (validation study, manufacturer's specification,
  rule of thumb).
- Origin distances as **intervals at stated muzzle heights**, together with
  `p_reachable`, and the assumptions behind the heights.
- Convergence as **consistent with**, never as proof of, a single position.
- Any **assumed** segment as an assumption, separately from the evidence.

The report template does all of this by default; see
`vignette("reports-and-3d")`.
