Calculate lens base curve and diameter based on keratometry readings.
BC and dia calculation algorithm is based on Soft Special Edition – Base Curve.
Calculate lens base curve and diameter based on keratometry readings.
BC and dia calculation algorithm is based on Soft Special Edition – Base Curve.
#!/usr/bin/env python | |
""" | |
Calculate lens BC (base curve) and diameter based on K readings (keratometry readings). | |
BC and dia calculation based on http://softspecialedition.com/base_curve | |
Glossary: | |
CL - Contact Lenses | |
OD - right patient's eye | |
OS - left patient's eye | |
HVID - horizontal visible iris diameter | |
K1 - flat meridian from keratometric readings | |
K2 - steep meridian from keratometric readings | |
VD - vertex distance | |
D - diopters | |
""" | |
import math | |
# Refractive readings (used to adjust prescription from glasses to contacts) | |
VD = 12.00 # mm. Set to 0 if it is your contact lens prescription | |
OD_Sph = +2.00 | |
OD_Cyl = -0.75 | |
OD_Axis = 20 | |
OS_Sph = +3.50 | |
OS_Cyl = -1.25 | |
OS_Axis = 176 | |
# Keratometry readings (used to calculate Base Curve and Diameter) | |
OD_HVID = 11.96 # mm | |
OD_Anterior_3mm_K1 = 38.72 # D | |
OD_Anterior_3mm_K2 = 39.17 # D | |
OD_Anterior_3mm_K_Avg = 38.94 # D, None if not specified | |
# OD_Anterior_3mm_K1_Axis = 20 # degrees | |
# OD_Anterior_3mm_K2_Axis = 110 # degrees | |
OS_HVID = 12.01 | |
OS_Anterior_3mm_K1 = 38.12 | |
OS_Anterior_3mm_K2 = 39.45 | |
OS_Anterior_3mm_K_Avg = 38.77 | |
# OS_Anterior_3mm_K1_Axis = 172 | |
# OS_Anterior_3mm_K2_Axis = 82 | |
# Constants | |
n0 = 1 # Refractive index of air | |
n1 = 1.3375 # Keratometric index | |
HVID_Avg = 11.8 # Average HVID discussed in the last issue of Soft Special Edition | |
def clamp(minimum, x, maximum): | |
return max(minimum, min(x, maximum)) | |
def round4(x): | |
""" 0.25 step """ | |
return round(x*4)/4 | |
def round8(x): | |
""" 0.125 step """ | |
return round(x*8)/8 | |
def main(): | |
OD_Toric = OD_Cyl is not None and OD_Axis is not None | |
OS_Toric = OS_Cyl is not None and OS_Axis is not None | |
def glassToContacts(sph, cyl): | |
# F_c = (F^(-1) - x)^(-1), where | |
# F_c is the power corrected for vertex distance, | |
# F is the original lens power, and | |
# x is the change in vertex distance in meters. | |
F_c1 = 1/((1/sph) - VD*0.001) | |
F_c2_uncorrected = sph + cyl | |
F_c2 = 1/((1/F_c2_uncorrected) - VD*0.001) | |
F_cyl = F_c2 - F_c1 | |
return F_c1, F_cyl | |
OD_CL_Sph, OD_CL_Cyl = glassToContacts(OD_Sph, OD_Cyl) | |
OS_CL_Sph, OS_CL_Cyl = glassToContacts(OS_Sph, OS_Cyl) | |
OD_CL_Axis, OS_CL_Axis = OD_Axis, OS_Axis | |
# Calculating CL Diameter | |
""" | |
Once the HVID is determined we add 2.0mm to the HVID to determine our overall lens diameter for a spherical lens | |
(eg. HVID = 12.0mm, overall lens diameter = 14.0mm). For a toric contact lens we add 2.5mm | |
(eg. HVID = 12.0mm, overall lens diameter = 14.5mm) to provide adequate limbal coverage and to aid in lens stabilization. | |
""" | |
OD_CL_Diameter = OD_HVID + (2.5 if OD_Toric else 2) | |
OS_CL_Diameter = OS_HVID + (2.5 if OS_Toric else 2) | |
# Calculating mean keratometric reading | |
OD_K_Mean = OD_Anterior_3mm_K_Avg or (OD_Anterior_3mm_K1 + OD_Anterior_3mm_K2) / 2 | |
OS_K_Mean = OS_Anterior_3mm_K_Avg or (OS_Anterior_3mm_K1 + OS_Anterior_3mm_K2) / 2 | |
# Calculating effective keratometric reading | |
""" | |
Determine the “effective K,” which is a number that embodies both the central keratometric readings and the HVID. | |
This is done be adding 1D to the mean K for every 0.2mm that the HVID is larger than 11.8mm | |
(this was the average HVID discussed in the last issue of Soft Special Edition) | |
and subtracting 1D from the mean K for every 0.2mm that the HVID is smaller than 11.8mm. | |
""" | |
OD_K_Effective = OD_K_Mean + (OD_HVID - HVID_Avg) * 5 | |
OS_K_Effective = OS_K_Mean + (OS_HVID - HVID_Avg) * 5 | |
# Convert Effective K to BC | |
OD_CL_BC_Calculated = (n1 - n0) * 1000 / OD_K_Effective | |
OS_CL_BC_Calculated = (n1 - n0) * 1000 / OS_K_Effective | |
# "Nomogram" impl. | |
def fitFlatter(lens_dia): | |
lens_dia = clamp(12, lens_dia, 16.5) | |
lens_dia = round(lens_dia * 2) / 2 # round to 0.5 | |
if math.isclose(lens_dia, 12): | |
return 0 | |
return (lens_dia - 12.5) * 2 * 0.20 + 0.10 | |
# Adjust | |
OD_CL_BC = OD_CL_BC_Calculated + fitFlatter(OD_CL_Diameter) | |
OS_CL_BC = OS_CL_BC_Calculated + fitFlatter(OS_CL_Diameter) | |
print(f"---") | |
print(f"OD_Sph: {OD_Sph:.2f}, OD_CL_Sph: {OD_CL_Sph:.2f}, rounded: {round4(OD_CL_Sph):+.2f} {round8(OD_CL_Sph):+.3f}") | |
print(f"OS_Sph: {OS_Sph:.2f}, OS_CL_Sph: {OS_CL_Sph:.2f}, rounded: {round4(OS_CL_Sph):+.2f} {round8(OS_CL_Sph):+.3f}") | |
print(f"OD_Cyl: {OD_Cyl:.2f}, OD_CL_Cyl: {OD_CL_Cyl:.2f}, rounded: {round4(OD_CL_Cyl):+.2f} {round8(OD_CL_Cyl):+.3f}") | |
print(f"OS_Cyl: {OS_Cyl:.2f}, OS_CL_Cyl: {OS_CL_Cyl:.2f}, rounded: {round4(OS_CL_Cyl):+.2f} {round8(OS_CL_Cyl):+.3f}") | |
print(f"OD_HVID: {OD_HVID:.2f} mm, OD_CL_Diameter: {OD_CL_Diameter:.2f} mm. BC will be flatter by {fitFlatter(OD_CL_Diameter):.2f} mm.") | |
print(f"OS_HVID: {OS_HVID:.2f} mm, OS_CL_Diameter: {OS_CL_Diameter:.2f} mm. BC will be flatter by {fitFlatter(OS_CL_Diameter):.2f} mm.") | |
print(f"OD_K_Mean: {OD_K_Mean:.2f} D, OD_K_Effective: {OD_K_Effective:.2f} D.") | |
print(f"OS_K_Mean: {OS_K_Mean:.2f} D, OS_K_Effective: {OS_K_Effective:.2f} D.") | |
print(f"OD_CL_BC_Calculated: {OD_CL_BC_Calculated:.2f} mm, OD_CL_BC: {OD_CL_BC:.2f} mm.") | |
print(f"OS_CL_BC_Calculated: {OS_CL_BC_Calculated:.2f} mm, OS_CL_BC: {OS_CL_BC:.2f} mm.") | |
print(f"---") | |
print(f"Based on your readings, your soft contact lenses should be:") | |
print(f"OD (right eye):") | |
print(f" Base Curve: {OD_CL_BC:.1f} mm") | |
print(f" Diameter: {OD_CL_Diameter:.1f} mm") | |
print(f" Sphere: {OD_CL_Sph:+.2f} (0.25 D step: {round4(OD_CL_Sph):+.2f}) (0.125 D step: {round8(OD_CL_Sph):+.3f})") | |
print(f" Cylinder: {OD_CL_Cyl:.2f} (0.25 D step: {round4(OD_CL_Cyl):+.2f}) (0.125 D step: {round8(OD_CL_Cyl):+.3f})") | |
print(f" Axis: {OD_CL_Axis:.0f}° (10° step: {round(OD_CL_Axis/10)*10})") | |
print(f" Based on nominal {VD:.0f} mm vertex distance") | |
print(f"OS (left eye):") | |
print(f" Base Curve: {OS_CL_BC:.1f} mm") | |
print(f" Diameter: {OS_CL_Diameter:.1f} mm") | |
print(f" Sphere: {OS_CL_Sph:+.2f} D (0.25 D step: {round4(OS_CL_Sph):+.2f}) (0.125 D step: {round8(OS_CL_Sph):+.3f})") | |
print(f" Cylinder: {OS_CL_Cyl:.2f} D (0.25 D step: {round4(OS_CL_Cyl):+.2f}) (0.125 D step: {round8(OS_CL_Cyl):+.3f})") | |
print(f" Axis: {OS_CL_Axis:.0f}° (10° step: {round(OS_CL_Axis/10)*10})") | |
print(f" Based on nominal {VD:.0f} mm vertex distance") | |
# Order custom lens: https://www.eyemaxxoutlet.com/c-vue-55-custom-toric-contact-lenses | |
if __name__ == '__main__': | |
main() |
---
OD_Sph: 2.00, OD_CL_Sph: 2.05, rounded: +2.00 +2.000
OS_Sph: 3.50, OS_CL_Sph: 3.65, rounded: +3.75 +3.625
OD_Cyl: -0.75, OD_CL_Cyl: -0.78, rounded: -0.75 -0.750
OS_Cyl: -1.25, OS_CL_Cyl: -1.34, rounded: -1.25 -1.375
OD_HVID: 11.96 mm, OD_CL_Diameter: 14.46 mm. BC will be flatter by 0.90 mm.
OS_HVID: 12.01 mm, OS_CL_Diameter: 14.51 mm. BC will be flatter by 0.90 mm.
OD_K_Mean: 38.94 D, OD_K_Effective: 39.74 D.
OS_K_Mean: 38.77 D, OS_K_Effective: 39.82 D.
OD_CL_BC_Calculated: 8.49 mm, OD_CL_BC: 9.39 mm.
OS_CL_BC_Calculated: 8.48 mm, OS_CL_BC: 9.38 mm.
---
Based on your readings, your soft contact lenses should be:
OD (right eye):
Base Curve: 9.4 mm
Diameter: 14.5 mm
Sphere: +2.05 (0.25 D step: +2.00) (0.125 D step: +2.000)
Cylinder: -0.78 (0.25 D step: -0.75) (0.125 D step: -0.750)
Axis: 20° (10° step: 20)
Based on nominal 12 mm vertex distance
OS (left eye):
Base Curve: 9.4 mm
Diameter: 14.5 mm
Sphere: +3.65 D (0.25 D step: +3.75) (0.125 D step: +3.625)
Cylinder: -1.34 D (0.25 D step: -1.25) (0.125 D step: -1.375)
Axis: 176° (10° step: 180)
Based on nominal 12 mm vertex distance