Unit Conversions

Table of Contents

1. Begin package

;;; unit-conversions.el --- Convert between units  -*- lexical-binding: t; -*-

;; Copyright 2024 Christian Gimenez
;;
;; Author: Christian Gimenez
;; Maintainer: Christian Gimenez
;; Version: 0.1.0
;; Keywords: convenience
;; URL: https://gitlab.com/cnngimenez/emacs-stuff
;; Package-Requires: ((emacs "27.1"))

;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <https://www.gnu.org/licenses/>.


;;; Commentary:

;; Functions to convert between length and other unit measures.

;;; Code:

2. Length

2.1. Absolute units

1 in = 2.54 cm = 25.4 mm = 72 pt = 6 pc

2.1.1. uc-length-equivalence   constant

(defconst uc-length-equivalence '((in . 1)
                           (cm . 2.54)
                           (pt . 72)
                           (pc . 6))
  "Equivalences between 1 inch and other unit measures.")

We implement the “three-simple” rule:

from-unit -- to-unit
amount -- X

2.1.2. uc-read-unit   function

(defun uc-read-unit (prompt)
  "Read from user with completion the unit.
PROMPT is a string with the prompt message for the user."
  (intern
   (completing-read prompt (mapcar #'car uc-length-equivalence))))

2.2. uc-convert   function

(defun uc-convert (amount from to)
  "Convert an amount between one unit measure to another.
FROM is a symbol with the unit name of AMOUNT (ex.: \\='cm, \\='in).
TO is as symbol with the unit name to convert.

For instance, to convert 25 cm into inches, use the following code:
  (uc-convert 25 \\='cm \\='in)"
  (interactive (list (read-number "Enter amount?")
                     (uc-read-unit "Amount unit?")
                     (uc-read-unit "Convert to?")))

  (let* ((from-unit (cdr (assoc from uc-length-equivalence)))
         (to-unit   (cdr (assoc to uc-length-equivalence)))
         (results   (/ (* to-unit amount) from-unit)))
    (when (called-interactively-p 'any)
      (message "%s %s = %s %s" amount from results to))
    results))

2.3. Relative or screen units

Screen units depends on the screen size and resolution. Therefore, a 1 cm line on a screen can have a different amount of pixels than in another screen.

2.3.1. Dots per inch

To associate between the screen and the absolute units, the dots per inch unit should be used. The dots per inch (dpi) specify the amount of dots (pixels) a line of 1 inch (2.54 cm = 25.4 mm) possess.

Common values for dpi are: 96 dpi, 100 dpi, 220 dpi, 1800 dpi. Then 0.25 mm = 0.025 cm = 1 px (using 100 dpi).

Table 1: Different lengths for each dpi values (for 1 px).
dpi in per px cm per px mm per px
96 0.010416667 0.026458334 0.26458334
100 0.01 0.0254 0.254
220 4.5454545e-3 0.011545454 0.11545454
1800 5.5555556e-4 1.4111111e-3 0.014111111

Usually, the most common dpi set on X11 in GNU/Linux is 96 dpi. Use xrandr -q to get the monitors values.

2.3.2. uc-convert-to-px   function

(defun uc-convert-to-px (from-amount from-unit &optional dpi)
  "Convert a measure into pixels.
Depending on the dots per inch (dpi), convert the given amount from the given
unit into pixels.

Parameters are:
FROM-AMOUNT the number of the measure.
FROM-UNIT is the symbol with the unit name.
DPI is the dots per inch value which is optional.

The common DPI values are 96, 100, 220, 1800.  This value depends on the
screen.  If not provided 96 is used."
  (interactive (list (read-number "Enter amount?")
                     (uc-read-unit  "Amount unit?")
                     (read-number "DPI?" 96)))

  (let* ((from-inches (if (equal from-unit 'in)
                          from-amount
                        (uc-convert from-amount from-unit 'in)))
         (dpi-num (or dpi 96))
         (results (if (equal from-unit 'in)
                      (* dpi-num from-inches)
                    (uc-convert (* dpi-num from-inches) 'in from-unit))))

    (when (called-interactively-p 'any)
      (message "%s %s = %s px (with %s dpi)" from-amount from-unit results dpi))

    results))

2.3.3. uc-convert-from-px   function

(defun uc-convert-from-px (px-amount to-unit &optional dpi)
  "Convert from px to the given measure unit.
PX-AMOUNT is the number of pixels to convert.
TO-UNIT is the symbol with the unit name.
DPI is the number of dots per inchs.

Usual DPI values are 96, 100, 220, and 1800, but it depends on the screen.
The default is 96."
  (interactive (list (read-number "Pixels amount?")
                     (uc-read-unit "Convert to?")
                     (read-number "DPI?" 96)))

  (let* ((dpi-num (or dpi 96))
         (px-unit (/ 1 dpi-num))
         (results (if (equal to-unit 'in)
                      (* px-unit px-amount)
                    (uc-convert (* px-unit px-amount) 'in to-unit))))

    (when (called-interactively-p 'any)
      (message "%s px = %s %s (with %s dpi)" px-amount results to-unit dpi))

    results))      

3. End package

(provide 'unit-conversions)
;;; unit-conversions.el ends here

4. Bibliography and useful resources

Date: 03 jul 2024

Author: Christian Gimenez

Created: 2024-11-04 lun 01:25

Validate