PHPackages                             theriftlab/radiance - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. theriftlab/radiance

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

theriftlab/radiance
===================

Conversions and operations between various angle and coordinate formats.

v1.1.8(2mo ago)08MITPHPPHP ^8.1

Since Dec 31Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/theriftlab/radiance)[ Packagist](https://packagist.org/packages/theriftlab/radiance)[ RSS](/packages/theriftlab-radiance/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (2)Versions (11)Used By (0)

Angle Alchemy
=============

[](#angle-alchemy)

Radiance provides simple, lightweight classes to make it easy for your PHP applications to deal with 360° circle-based angles, such as converting between various formats, adding and subtracting, normalizing, and finding distances and midpoints.

Installation
------------

[](#installation)

**NOTE:** Radiance requires PHP ^8.1 and the [BCMath](https://www.php.net/manual/en/book.bc.php) extension.

```
composer require theriftlab/radiance
```

Usage
-----

[](#usage)

### Examples

[](#examples)

Radiance offers three main classes: `Angle`, `Latitude` and `Longitude`. Being fairly simple classes, their underlying structure is much the same, with only a few differences.

```
use RiftLab\Radiance\Angle;

$angle = Angle::make(-51.477928);

echo $angle;
// Output: -51°28'41"

$angle2 = Angle::make('10°');

echo $angle->distanceTo($angle2);
// Output: 61°28'41"
echo $angle->distanceFrom($angle2);
// Output: -61°28'41"
echo $angle2->distanceTo($angle);
// Output: -61°28'41"
echo $angle->distanceTo(10);
// Output: 61°28'41"

echo $angle->add($angle2);
// Output: -41°28'41"
echo $angle->add(10);
// Output: -41°28'41"
echo $angle->sub($angle2);
// Output: -61°28'41"
echo $angle->sub(10);
// Output: -61°28'41"
echo $angle->add($angle2)->distanceTo($angle);
// Output: -10°00'00"

echo Angle::make(350)->midpointWith(20);
// Output: 05°00'00
```

### Instantiation

[](#instantiation)

Objects can be constructed from almost any format. A few more examples using `Angle`:

```
// These will all produce identical objects:
$angle1 = Angle::make(-51.477928);
$angle2 = Angle::make('-51°28\'40.5408"');
$angle3 = Angle::make('51°28\'40.5408"W');
$angle4 = Angle::make('51w28\'40.5408');
$angle5 = Angle::make('51s28.67568');

var_dump($angle1 == $angle2);
// Output: bool(true)
var_dump($angle2 == $angle3);
// Output: bool(true)
// ..etc.
```

### Coordinate Classes

[](#coordinate-classes)

In addition to the basic `Angle` class, there are also `Latitude` and `Longitude` classes. These behave the same as the `Angle` class, only they are limited to their geographical boundaries: -90° to 90° for `Latitude` and -180° to 180° for `Longitude`. Attempting to instantiate with angles outside these limits, or to `add()` / `sub()` values that would push them outside of these limits, will throw an exception.

Although the output for all types can be customized (see the [String Formatting](#string-formatting) section below), the only other difference with the coordinate classes is their default string format:

```
$lat = Latitude::make(-51.477928);
echo $lat;
// Output: 51s28.68

echo $lat->add(60);
// Output: 8n31.32

echo $lat->midpointWith(10);
// Output: 20s44.34

echo $lat->sub(40);
// Below -90°: LatitudeBoundaryError thrown

$dist = Angle::make(40);
echo $lat->sub($dist);
// LatitudeBoundaryError still thrown
```

### Negative Angles

[](#negative-angles)

Radiance is fairly non-opinionated about the angles you wish to represent with an `Angle` instance. You can construct one from a negative angle, although it will be normalized:

```
echo Angle::make(-560);
// Output: -200°0'0"
```

However, since the `distanceTo()` / `distanceFrom()` and `midpointWith()` calculations are designed to find the shortest distance between two points on a 0-360° circle, using negative angles might yield results that appear less than intuitive at first glance:

```
$angle = Angle::make(-200);     // 160° on a circle

echo $angle;
// Output: -200°0'0"
echo $angle->distanceTo(140);   // 160° to 140°
// Output: -20°0'0"
echo $angle->distanceTo(180);   // 160° to 180°
// Output: 20°0'0"
```

If we get really weird and mix our negatives, they still stack up:

```
$angle = Angle::make(-560);     // still 160°

echo $angle;
// Output: -200°0'0"
echo $angle->distanceTo(-220);  // 140° on a circle, so still 160° to 140°
// Output: -20°0'0"
echo $angle->distanceTo(-180);  // 180° on a circle, so still 160° to 180°
// Output: 20°0'0"
```

### Diffs

[](#diffs)

Although not designed for direct instantiation, an instance of the `Diff` class is returned for all `distanceTo()` and `distanceFrom()` operations. This is essentially the same as the `Angle` class but limited to output functionality only, without any further operations available. Its default formatting will reflect whatever class it is calculated from:

```
echo Angle::make(10)->distanceTo(30);
// Output: 20°00'00"

echo Latitude::make(10)->distanceTo(30);
// Output: 20n0.00

echo Longitude::make(10)->distanceTo(30);
// Output: 20e0.00
```

See the [String Formatting](#string-formatting) section below for details on how to customize the output.

### Functions

[](#functions)

The following functions are available for all class types, including `Diff`:

MethodReturn TypeParametersDefaultDescription`isNegative()``bool`NoneNoneReturns whether the angle is negative.`getDegrees()``float``int $decimalPlaces``null`Returns the unsigned degrees portion of the angle. If `$decimalPlaces` is set to `-1` it will be `floor()`ed, and passing `0` and upward will round it as normal. The default `null` will round to 8 decimal places.`getMinutes()``float``int $decimalPlaces``null`The same as above but for minutes.`getSeconds()``float``int $decimalPlaces``null`The same as above but for seconds.`toDecimal()``float``int $decimalPlaces``null`The same as above but returns the underlying `float` angle. Essentially the same as `getDegrees()` but signed. Since PHP's `float` type is limited to 14 significant digits, if you require more precision then use the `toRawDecimal()` function described below.`toRawDecimal()``string`NoneNoneReturns the angle's underlying BCMath string.`toArray()``array`NoneNoneReturns an array with the following elements:
\* `direction`: either `-` or `+`.
\* `degrees`: floored `int` representing degrees.
\* `minutes`: floored `int` representing minutes.
\* `seconds`: a `float` representing seconds, rounded to 8 decimal places.`toString()``string``string $format`Dependent on typeFormats the angle as requested. See the [String Formatting](#string-formatting) section below for details. Calling this with no arguments will yield the default format depending on the calling instance's class type, as demonstrated in the examples above.The following additional operations are available for the `Angle`, `Latitude` and `Longitude` classes which implement `AngleInterface`:

MethodReturn TypeParametersDefaultDescription`add()`self`AngleInterface | float $angle`NoneAdds either another `AngleInterface` instance or a float, and returns a new instance of the calling class' type constructed from the result.`sub()`self`AngleInterface | float $angle`NoneThe same as above but for subtraction.`distanceTo()``Diff``AngleInterface | float $angle`NoneCalculates the shortest distance on a circle between the calling instance and the passed `AngleInterface` instance or float, and returns a new instance of the calling class' type constructed from the result. As seen in the examples above, the result will be negative if the passed angle is behind the first, and positive if ahead.`distanceFrom()``Diff``AngleInterface | float $angle`NoneThe inverse of the above function.`midpointWith()`self`AngleInterface | float $angle`NoneCalculates the midpoint of the shortest distance on a circle between the calling instance and the passed `AngleInterface` instance or float, and returns a new instance of the calling class' type constructed from the result.The `Angle` class itself has one additional function:

MethodReturn TypeParametersDefaultDescription`normalizeTo()``Angle``int $size`NoneNormalizes the angle to the passed integer and returns a new `Angle` instance constructed from the result. For example, if a circle is split into quadrants and you only wish to know the angle within its own quadrant, you would pass `90` to this function.### String Formatting

[](#string-formatting)

The `toString()` function accepts a string of placeholders to dictate its formatting. The default format strings for each class type are as follows:

ClassFormat StringOutput`Angle``'{D}{dd.-1}°{mm.-1}\'{ss.0}"'`Degrees, minutes, and seconds with leading zeroes. Seconds are rounded, and the output is prefixed by a `-` sign if negative.`Latitude``'{d.-1}{D}{m.2f}'`Geographical latitude. Degrees, North / South direction, and a decimal minute rounded to two places.`Longitude``'{d.-1}{D}{m.2f}'`Geographical longitude. Similar to above: degrees, West / East direction, and a decimal minute rounded to two places.To pass your own format, the following placeholders are available for all class types:

PlaceholderOutput`{S}`Sign: a `-` symbol if the angle is negative, otherwise nothing.`{SS}`Sign: a `-` symbol if the angle is negative, otherwise `+`.`{d.X}`Degrees, rounded to `X` places, with `X` being analogous to the `$decimalPlaces` parameter described above in the [functions](#functions) table. To force `X` amount of decimal places regardless of trailing zeros, append `f` - eg. for 23.5° `{d.2}` will output `23.5` vs `{d.2f}` which will output `23.50`. To pass `null` simply omit the decimal point, ie. `{d}`.`{m.X}`The same as above, but for minutes.`{s.X}`The same as above, but for seconds.`{dd.X}`Degrees as above, but with leading zero to ensure double digits.`{mm.X}`The same as above, but for minutes.`{ss.X}`The same as above, but for seconds.For the `Latitude` class only, the following additional placeholders are available:

PlaceholderOutput`{D}`Direction: a lowercase `s` if the angle is negative, otherwise lowercase `n`.`{DD}`Direction: the same as above but uppercase.For the `Longitude` class only, the following additional placeholders are available:

PlaceholderOutput`{D}`Direction: a lowercase `w` if the angle is negative, otherwise lowercase `e`.`{DD}`Direction: the same as above but uppercase.Tests
-----

[](#tests)

Tests are included via Pest:

```
./vendor/bin/pest
```

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance86

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~88 days

Recently: every ~197 days

Total

10

Last Release

71d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/7fa1c8a793c191b44ce81ec9670006610345c5b782d6d09edc749870a57ea951?d=identicon)[theriftlab](/maintainers/theriftlab)

---

Top Contributors

[![theriftlab](https://avatars.githubusercontent.com/u/370745?v=4)](https://github.com/theriftlab "theriftlab (38 commits)")

---

Tags

anglescalculationcirclecoordinatesdegreesdegrees-minutes-secondsgeolocationlatitudelongitudemidpoint

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/theriftlab-radiance/health.svg)

```
[![Health](https://phpackages.com/badges/theriftlab-radiance/health.svg)](https://phpackages.com/packages/theriftlab-radiance)
```

###  Alternatives

[cartalyst/collections

Collection Abstaction library for PHP.

76908.6k4](/packages/cartalyst-collections)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
