--- a/UnitConverter.st Thu Aug 31 14:54:32 2017 +0200
+++ b/UnitConverter.st Mon Sep 18 09:07:02 2017 +0200
@@ -1,5 +1,3 @@
-"{ Encoding: utf8 }"
-
"
COPYRIGHT (c) 1996 eXept Software AG
All Rights Reserved
@@ -386,8 +384,10 @@
"/ ---------------- temperature ----------------
- self addConversion:[:d | d * 1.8 + 32] from:#celsius to:#fahrenheit.
+ self addConversion:[:d | d * 1.8 + 32] from:#celsius to:#fahrenheit.
self addConversion:[:f | (f - 32) / 1.8] from:#fahrenheit to:#celsius.
+ self addConversion:[:d | d + 273.15] from:#celsius to:#kelvin.
+ self addConversion:[:k | k - 273.15] from:#kelvin to:#celsius.
"/ ---------------- nature ----------------
Constants at:#planckLength put:#(1.616e-35 #'m').
@@ -399,8 +399,8 @@
UnitConverter initializeConversions
"
- "Created: / 22.7.1997 / 13:56:40 / cg"
- "Modified: / 10.10.2001 / 14:39:04 / cg"
+ "Created: / 22-07-1997 / 13:56:40 / cg"
+ "Modified: / 18-09-2017 / 08:38:14 / cg"
!
initializePrintValues
@@ -577,6 +577,55 @@
to destUnit (symbolic); return nil, if the conversion is
unknown."
+ ^ self convert:howMany from:sourceUnit to:destUnit pairsAlreadyTried:(OrderedCollection new)
+
+ "direct - how many meters are there in two inches:
+ UnitConverter convert:2 from:#inch to:#meter
+
+ reverse - how many inches are there in one meter
+ UnitConverter convert:1 from:#meter to:#inch
+
+ with alias:
+ UnitConverter convert:1 from:#inch to:#m
+ UnitConverter convert:1 from:#inch to:#mm
+ UnitConverter convert:1 from:#inch to:#millimeter
+ UnitConverter convert:1 from:#inch to:#nanometer
+ UnitConverter convert:1 from:#mm to:#km
+ UnitConverter convert:1 from:#km to:#foot
+
+ indirect:
+ UnitConverter convert:1 from:#mm to:#twip
+ UnitConverter convert:1 from:#inch to:#twip
+ UnitConverter convert:1 from:'letterH' to:#point
+ UnitConverter convert:1 from:'letterlH' to:#point
+
+ UnitConverter convert:5 from:#barrel to:#liter
+ UnitConverter convert:10 from:#kilogram to:#carat
+
+ UnitConverter convert:1 from:#liter to:#floz
+ UnitConverter convert:1 from:#floz to:#liter
+ UnitConverter convert:1 from:#oz to:#gram
+ UnitConverter convert:1 from:#ounce to:#gram
+
+ UnitConverter convert:37 from:#celsius to:#fahrenheit -> 98.6
+ UnitConverter convert:37 from:#celsius to:#kelvin -> 310.15
+ UnitConverter convert:0 from:#celsius to:#kelvin -> 273.15
+ UnitConverter convert:0 from:#kelvin to:#celsius -> -273.15
+ UnitConverter convert:0 from:#kelvin to:#fahrenheit -> -459.67
+ UnitConverter convert:0 from:#fahrenheit to:#celsius -> -17.7777777777778
+ UnitConverter convert:0 from:#fahrenheit to:#kelvin -> 255.372222222222
+
+ "
+
+ "Created: / 31-05-1996 / 16:23:38 / cg"
+ "Modified (comment): / 18-09-2017 / 09:02:09 / cg"
+!
+
+convert:howMany from:sourceUnit to:destUnit pairsAlreadyTried:pairsAlready
+ "given a value in sourceUnit (symbolic), try to convert it
+ to destUnit (symbolic); return nil, if the conversion is
+ unknown."
+
|u conversions alias rslt sU dU const val unit
i suNumerator suDenominator duNumerator duDenominator uN uD
sF1 sF2 dF1 dF2
@@ -592,17 +641,24 @@
sourceUnit == destUnit ifTrue:[
^ howMany
].
-
+ thisContext isReallyRecursive ifTrue:[
+ ^ self noConversionFrom:sourceUnit to:destUnit.
+ ].
+ (pairsAlready includes:(sourceUnit->destUnit)) ifTrue:[
+ ^ self noConversionFrom:sourceUnit to:destUnit.
+ ].
+ pairsAlready add:(sourceUnit->destUnit).
+
sourceUnit isSymbol ifFalse:[
s := sourceUnit withoutSeparators.
sU := s asSymbolIfInterned.
sU notNil ifTrue:[
- ^ self convert:howMany from:sU to:destUnit
+ ^ self convert:howMany from:sU to:destUnit pairsAlreadyTried:pairsAlready
].
(s startsWith:$() ifTrue:[
(s endsWith:$)) ifTrue:[
s := s copyFrom:2 to:(s size - 1).
- ^ self convert:howMany from:s to:destUnit
+ ^ self convert:howMany from:s to:destUnit pairsAlreadyTried:pairsAlready
]
].
].
@@ -610,12 +666,12 @@
d := destUnit withoutSeparators.
dU := d asSymbolIfInterned.
dU notNil ifTrue:[
- ^ self convert:howMany from:sourceUnit to:dU
+ ^ self convert:howMany from:sourceUnit to:dU pairsAlreadyTried:pairsAlready
].
(d startsWith:$() ifTrue:[
(d endsWith:$)) ifTrue:[
d := d copyFrom:2 to:(d size - 1).
- ^ self convert:howMany from:sourceUnit to:d
+ ^ self convert:howMany from:sourceUnit to:d pairsAlreadyTried:pairsAlready
]
].
].
@@ -624,23 +680,23 @@
u := self unscaled:sourceUnit.
u notNil ifTrue:[
- ^ self convert:(howMany*(u value)) from:(u key) to:destUnit
+ ^ self convert:(howMany*(u value)) from:(u key) to:destUnit pairsAlreadyTried:pairsAlready
].
u := self unscaled:destUnit.
u notNil ifTrue:[
- ^ self convert:(howMany/(u value)) from:sourceUnit to:(u key)
+ ^ self convert:(howMany/(u value)) from:sourceUnit to:(u key) pairsAlreadyTried:pairsAlready
].
"/ and of aliases ...
alias := Aliases at:sourceUnit ifAbsent:nil.
alias notNil ifTrue:[
- ^ self convert:howMany from:alias to:destUnit
+ ^ self convert:howMany from:alias to:destUnit pairsAlreadyTried:pairsAlready
].
alias := Aliases at:destUnit ifAbsent:nil.
alias notNil ifTrue:[
- ^ self convert:howMany from:sourceUnit to:alias
+ ^ self convert:howMany from:sourceUnit to:alias pairsAlreadyTried:pairsAlready
].
"/ any constants ?
@@ -649,7 +705,7 @@
const := Constants at:sourceUnit.
val := const at:1.
unit := const at:2.
- ^ self convert:(howMany*val) from:unit to:destUnit
+ ^ self convert:(howMany*val) from:unit to:destUnit pairsAlreadyTried:pairsAlready
].
"/ compounds (^ , / or *) are very naively parsed
@@ -663,7 +719,7 @@
sU := (sourceUnit copyButLast:2) asSymbolIfInterned.
dU := (destUnit copyButLast:2) asSymbolIfInterned.
(sU notNil and:[dU notNil]) ifTrue:[
- ^ (self convert:(howMany sqrt) from:sU to:dU) squared
+ ^ (self convert:(howMany sqrt) from:sU to:dU pairsAlreadyTried:pairsAlready) squared
].
^ self noConversionFrom:sourceUnit to:destUnit.
].
@@ -671,7 +727,7 @@
sU := (sourceUnit copyButLast:2) asSymbolIfInterned.
dU := (destUnit copyButLast:2) asSymbolIfInterned.
(sU notNil and:[dU notNil]) ifTrue:[
- ^ (self convert:(howMany raisedTo:(1/3)) from:sU to:dU) raisedTo:3
+ ^ (self convert:(howMany raisedTo:(1/3)) from:sU to:dU pairsAlreadyTried:pairsAlready) raisedTo:3
].
^ self noConversionFrom:sourceUnit to:destUnit.
].
@@ -687,9 +743,9 @@
duNumerator := destUnit copyTo:(i - 1).
duDenominator := destUnit copyFrom:(i + 1).
- uN := self convert:howMany from:suNumerator to:duNumerator.
+ uN := self convert:howMany from:suNumerator to:duNumerator pairsAlreadyTried:pairsAlready.
uN notNil ifTrue:[
- uD := self convert:1 from:suDenominator to:duDenominator.
+ uD := self convert:1 from:suDenominator to:duDenominator pairsAlreadyTried:pairsAlready.
uD notNil ifTrue:[
^ uN / uD
]
@@ -706,9 +762,9 @@
dF1 := destUnit copyTo:(i - 1).
dF2 := destUnit copyFrom:(i + 1).
- u := self convert:howMany from:sF1 to:dF1.
+ u := self convert:howMany from:sF1 to:dF1 pairsAlreadyTried:pairsAlready.
u notNil ifTrue:[
- u := self convert:u from:sF2 to:dF2.
+ u := self convert:u from:sF2 to:dF2 pairsAlreadyTried:pairsAlready.
u notNil ifTrue:[
^ u
]
@@ -723,22 +779,36 @@
rslt notNil ifTrue:[^ rslt].
"/ try inverse conversion ...
+ "/ but here, only linear factors (numeric conversions) are allowed!!
+ [
+ |conversions revFactor|
+
+ conversions := Conversions at:destUnit ifAbsent:nil.
+ conversions notNil ifTrue:[
+ revFactor := conversions at:sourceUnit ifAbsent:nil.
+ revFactor isNumber ifTrue:[
+ ^ howMany / revFactor
+ ].
+ ].
+ ] value.
- rslt := self convertDirect:1 from:destUnit to:sourceUnit.
- rslt notNil ifTrue:[ ^ howMany / rslt].
-
+
"/ here's the deep recursion ...
-
"/ try indirect conversion from source
-
conversions := Conversions at:sourceUnit ifAbsent:nil.
conversions notNil ifTrue:[
conversions keysAndValuesDo:[:intermediateUnit :factor1 |
- |factor2|
+ |factor2 intermediateValue result|
- factor2 := self convert:factor1 from:intermediateUnit to:destUnit.
- factor2 notNil ifTrue:[^ factor2 * howMany].
+ factor1 isBlock ifTrue:[
+ intermediateValue := factor1 value:howMany.
+ result := self convert:intermediateValue from:intermediateUnit to:destUnit pairsAlreadyTried:pairsAlready.
+ result notNil ifTrue:[ ^ result ].
+ ] ifFalse:[
+ factor2 := self convert:factor1 from:intermediateUnit to:destUnit pairsAlreadyTried:pairsAlready.
+ factor2 notNil ifTrue:[^ factor2 * howMany].
+ ].
].
].
@@ -749,8 +819,10 @@
conversions keysAndValuesDo:[:intermediateUnit :factor1 |
|factor2|
- factor2 := self convert:(factor1) from:intermediateUnit to:sourceUnit.
- factor2 notNil ifTrue:[^ howMany / factor2].
+ factor1 isBlock ifFalse:[
+ factor2 := self convert:(factor1) from:intermediateUnit to:sourceUnit pairsAlreadyTried:pairsAlready.
+ factor2 notNil ifTrue:[^ howMany / factor2].
+ ].
].
].
@@ -773,11 +845,10 @@
"/ what about c->b ?
iUnit := aUnit copyFrom:pref size + 1.
- factor2 := self convert:1 from:sF2 to:iUnit.
+ factor2 := self convert:1 from:sF2 to:iUnit pairsAlreadyTried:pairsAlready.
factor2 notNil ifTrue:[
"/ good ...
- rslt := self convert:(factor2 * howMany)
- from:aUnit to:destUnit.
+ rslt := self convert:(factor2 * howMany) from:aUnit to:destUnit pairsAlreadyTried:pairsAlready.
rslt notNil ifTrue:[^ rslt].
]
]
@@ -811,10 +882,14 @@
UnitConverter convert:10 from:#kilogram to:#carat
UnitConverter convert:1 from:#liter to:#floz
+ UnitConverter convert:0 from:#fahrenheit to:#kelvin
+ UnitConverter convert:0 from:#fahrenheit to:#celsius
+ UnitConverter convert:0 from:#celsius to:#kelvin
+ UnitConverter convert:0 from:#kelvin to:#celsius
"
- "Created: 31.5.1996 / 16:23:38 / cg"
- "Modified: 6.8.1997 / 18:10:22 / cg"
+ "Created: / 17-09-2017 / 10:11:40 / cg"
+ "Modified: / 18-09-2017 / 08:39:15 / cg"
!
fileSizeBinaryStringFor:nBytes
@@ -1326,7 +1401,7 @@
!UnitConverter class methodsFor:'private'!
-addConversion:factor from:sourceMetric to:destMetric
+addConversion:factorOrBlock from:sourceMetric to:destMetric
"add a conversion"
|conversion|
@@ -1336,7 +1411,7 @@
conversion := IdentityDictionary new.
Conversions at:sourceMetric put:conversion
].
- conversion at:destMetric put:factor.
+ conversion at:destMetric put:factorOrBlock.
^ conversion
"Created: 31.5.1996 / 13:51:25 / cg"