WindowingTransformation.st
changeset 78 1c9c22df3251
parent 72 3e84121988c3
child 81 4ba554473294
--- a/WindowingTransformation.st	Fri Oct 28 04:16:56 1994 +0100
+++ b/WindowingTransformation.st	Fri Oct 28 04:20:20 1994 +0100
@@ -23,9 +23,106 @@
 COPYRIGHT (c) 1992 by Claus Gittinger
 	      All Rights Reserved
 
-$Header: /cvs/stx/stx/libview/WindowingTransformation.st,v 1.6 1994-10-10 02:34:07 claus Exp $
+$Header: /cvs/stx/stx/libview/WindowingTransformation.st,v 1.7 1994-10-28 03:18:22 claus Exp $
 '!
 
+!WindowingTransformation class methodsFor:'documentation '!
+
+copyright
+"
+ COPYRIGHT (c) 1992 by Claus Gittinger
+	      All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+"
+!
+
+version
+"
+$Header: /cvs/stx/stx/libview/WindowingTransformation.st,v 1.7 1994-10-28 03:18:22 claus Exp $
+"
+!
+
+documentation
+"
+    instances of WindowingTransformation can be used to scale, translate or
+    generally transform other objects in 2D space. 
+    They can also be set as the translation in a graphic context, 
+    which will then apply this to all of its drawing operations 
+    (see GraphicContext>>transformation:).
+
+    All 2-D objects are supposed to be able to be transformed using
+    instances of me.  Multiple instances of me can also be combined to form a
+    single composite transformation.
+
+    Instance variables are:
+	scale           <Number> or <Point> representing a linear scaling factor.
+			nil is interpreted as 1@1
+
+	translation     <Number> or <Point> representing a translation in 2-D.
+			nil is interpreted as 0@0
+
+
+    example (drawing in inches):
+
+     |v|
+
+     v := View new realize.
+     (Delay forSeconds:3) wait.
+     v transformation:(WindowingTransformation unit:#inch on:Display).
+     'now, we can think of drawing in inches ...'.
+     v displayLineFrom:0.5@0.5 to:1@1 
+
+
+    example (drawing in millimeters):
+
+     |v|
+
+     v := View new realize.
+     (Delay forSeconds:3) wait.
+     v transformation:(WindowingTransformation unit:#mm on:Display).
+     'now, we can think of drawing in millimeters ...'.
+     v displayLineFrom:5@5 to:20@5 
+
+
+    example (drawing magnified):
+
+     |v|
+
+     v := View new realize.
+     (Delay forSeconds:3) wait.
+     v transformation:(WindowingTransformation scale:2 translation:0).
+     'now, everything is magnfied by 2'.
+     v displayLineFrom:10@10 to:30@30 
+
+
+    example (drawing shrunk):
+
+     |v|
+
+     v := View new realize.
+     (Delay forSeconds:3) wait.
+     v transformation:(WindowingTransformation scale:0.5 translation:0).
+     'now, everything is shrunk by 2'.
+     v displayLineFrom:10@10 to:30@30 
+
+
+     example (transforming Points, Rectangles etc.)
+
+
+      |p pNew|
+
+      p := 10@10.
+      pNew := (WindowingTransformation scale:2 translation:10) applyTo:p.
+      pNew
+"
+! !
+
 !WindowingTransformation class methodsFor:'instance creation'!
 
 unit:unitSymbol on:device 
@@ -61,20 +158,49 @@
 			pixelPerUnitH := device horizontalPixelPerInch 
 		    ] ifFalse:[
 			"sorry: unknown unit is taken as pixel"
-			^ self new scale:nil translation:(0 @ 0)
+			^ self new scale:nil translation:nil
 		    ]
 		]
 	    ]
 	]
     ].
-    ^ self new scale:(pixelPerUnitH @ pixelPerUnitV) translation:0
+    ^ self basicNew scale:(pixelPerUnitH @ pixelPerUnitV) translation:nil
+
+    "
+     |v|
+
+     v := View new realize.
+     (Delay forSeconds:3) wait.
+     v transformation:(WindowingTransformation unit:#inch on:Display).
+     'now, we can think of drawing in inches ...'.
+     v displayLineFrom:0.5@0.5 to:1@1 
+    "
 !
 
 scale:aScale translation:aTranslation 
     "returns a windowing transformation with a scale factor of  
      aScale and a translation offset of aTranslation."
 
-    ^ self new scale:aScale translation:aTranslation
+    ^ self basicNew scale:aScale translation:aTranslation
+
+    "
+     |v|
+
+     v := View new realize.
+     (Delay forSeconds:3) wait.
+     v transformation:(WindowingTransformation scale:2 translation:0).
+     'now, everything is magnfied by 2'.
+     v displayLineFrom:10@10 to:30@30 
+    "
+    "
+     |v|
+
+     v := View new realize.
+     (Delay forSeconds:3) wait.
+     v transformation:(WindowingTransformation scale:0.5 translation:0).
+     'now, everything is shrunk by 2'.
+     v displayLineFrom:10@10 to:30@30 
+    "
 !
 
 window:sourceRectangle viewport:destinationRectangle 
@@ -85,61 +211,42 @@
      represents the logical coordinateSpace while destinationRectangle 
      represents the device coordinateSpace."
 
-    |sX sY tX tY newScale|
+    |sX sY tX tY newScale newTranslation|
 
     sX := destinationRectangle width / sourceRectangle width.
     sY := destinationRectangle height / sourceRectangle height.
     tX := destinationRectangle left - sourceRectangle left.
     tY := destinationRectangle top - sourceRectangle top.
+    ((tX = 1.0) and:[tY = 1.0]) ifTrue:[
+	newTranslation := nil
+    ] ifFalse:[
+	newTranslation := tX @ tY
+    ].
     ((sX = 1.0) and:[sY = 1.0]) ifTrue:[
-	newScale := 1 @ 1
+	newScale := nil
     ] ifFalse:[
 	newScale := sX @ sY
     ].
-    ^ self new scale:newScale translation:(tX @ tY)
+    ^ self basicNew scale:newScale translation:newTranslation
+
+    "
+     |v|
+
+     v := View new realize.
+     (Delay forSeconds:3) wait.
+     v transformation:(WindowingTransformation 
+				window:(0@0 corner:1@1)
+				viewport:(0@0 corner:100@100)).
+     'now, we can think of drawing in 0..1/0..1 coordinates'.
+     v displayLineFrom:0.1@0.1 to:0.9@0.9 
+    "
 !
 
 identity
-    "returns a windowing transformation with no scaling (nil) 
+    "returns a windowing transformation with no scaling (1@1) 
      and no translation (0@0)."
 
-    ^ self new scale:1 translation:0
-! !
-
-!WindowingTransformation class methodsFor:'documentation'!
-
-copyright
-"
- COPYRIGHT (c) 1992 by Claus Gittinger
-	      All Rights Reserved
-
- This software is furnished under a license and may be used
- only in accordance with the terms of that license and with the
- inclusion of the above copyright notice.   This software may not
- be provided or otherwise made available to, or used by, any
- other person.  No title to or ownership of the software is
- hereby transferred.
-"
-!
-
-version
-"
-$Header: /cvs/stx/stx/libview/WindowingTransformation.st,v 1.6 1994-10-10 02:34:07 claus Exp $
-"
-!
-
-documentation
-"
-    I represent the ability to perform transformations in 2-D space.
-
-    Instance variables are:
-	scale           <Number> or <Point> representing a linear scaling factor.
-	translation     <Number> or <Point> representing a translation in 2-D.
-
-    All 2-D objects are supposed to be able to be transformed using
-    instances of me.  Instances of me can also be combined to form a
-    single composite transformation.
-"
+    ^ self basicNew scale:nil translation:nil 
 ! !
 
 !WindowingTransformation methodsFor:'applying transform'!
@@ -148,47 +255,36 @@
     "Apply the receiver to a number representing an x-coordinate
      and return the result."
 
-    scale isNil ifTrue:[
-	^ aNumber + translation x
-    ].
-    ^ (aNumber * scale x + translation x) asInteger
+    |t s|
+
+    scale isNil ifTrue:[s := 1] ifFalse:[s := scale x].
+    translation isNil ifTrue:[t := 0] ifFalse:[t := translation x].
+    ^ aNumber * s + t
 !
 
 applyToY:aNumber
     "Apply the receiver to a number representing an y-coordinate
      and return the result."
 
-    scale isNil ifTrue:[
-	^ aNumber + translation y
-    ].
-    ^ (aNumber * scale y + translation y) asInteger
+    |t s|
+
+    scale isNil ifTrue:[s := 1] ifFalse:[s := scale y].
+    translation isNil ifTrue:[t := 0] ifFalse:[t := translation y].
+    ^ aNumber * s + t
+!
+
+applyScaleX:aNumber
+    "apply the scale only (if widths are to be transformed)"
+
+    scale isNil ifTrue:[^ aNumber].
+    ^ aNumber * scale x
 !
 
 applyScaleY:aNumber
     "apply the scale only (if heights are to be transformed)"
 
     scale isNil ifTrue:[^ aNumber].
-    ^ (aNumber * scale y) asInteger
-!
-
-applyScaleX:aNumber
-    "apply the scale only (if widths are to be transformed)"
-
-    scale isNil ifTrue:[^ aNumber].
-    ^ (aNumber * scale x) asInteger
-!
-
-applyInverseTo:anObject 
-    "Apply the inverse of the receiver to anObject
-     and return the result."
-
-    |transformedObject|
-
-    transformedObject := anObject translatedBy:(self inverseTranslation).
-    scale == nil ifFalse:[
-	transformedObject scaleBy:(self inverseScale)
-    ].
-    ^ transformedObject
+    ^ aNumber * scale y
 !
 
 applyTo:anObject 
@@ -196,14 +292,92 @@
 
     |transformedObject|
 
-    scale == nil ifTrue:[
-	^ anObject translateBy:translation.
+    scale isNil ifTrue:[
+	translation isNil ifTrue:[
+	    ^ anObject
+	].
+	^ anObject translatedBy:translation 
+    ].
+    transformedObject := anObject scaledBy:scale.
+    translation notNil ifTrue:[
+	transformedObject translateBy:translation.
     ].
-    transformedObject := anObject scaledBy:scale
-    transformedObject translateBy:translation.
     ^ transformedObject
 !
 
+applyInverseToX:aNumber
+    "Apply the receiver to a number representing an x-coordinate
+     and return the result."
+
+    |t s|
+
+    scale isNil ifTrue:[s := 1] ifFalse:[s := scale x].
+    translation isNil ifTrue:[t := 0] ifFalse:[t := translation x].
+    ^ (aNumber - t) / s
+!
+
+applyInverseToY:aNumber
+    "Apply the receiver to a number representing an y-coordinate
+     and return the result."
+
+    |t s|
+
+    scale isNil ifTrue:[s := 1] ifFalse:[s := scale y].
+    translation isNil ifTrue:[t := 0] ifFalse:[t := translation y].
+    ^ (aNumber - t) / s
+!
+
+applyInverseScaleX:aNumber
+    "apply the scale only (if widths are to be transformed)"
+
+    scale isNil ifTrue:[^ aNumber].
+    ^ aNumber / scale x
+!
+
+applyInverseScaleY:aNumber
+    "apply the scale only (if heights are to be transformed)"
+
+    scale isNil ifTrue:[^ aNumber].
+    ^ aNumber / scale y
+!
+
+applyInverseTo:anObject 
+    "Apply the inverse of the receiver to anObject
+     and return the result. This can be used to map back from logical
+     to physical coordinates, for example."
+
+    |transformedObject|
+
+    translation isNil ifTrue:[
+	scale isNil ifTrue:[
+	    ^ anObject
+	].
+	^ anObject scaledBy:self inverseScale 
+    ].
+    transformedObject := anObject translatedBy:(self inverseTranslation).
+    scale notNil ifTrue:[
+	transformedObject scaleBy:(self inverseScale).
+    ].
+    ^ transformedObject
+!
+
+transformPoint:p 
+    "Apply the receiver to a point.
+     This is destructive in that the point is being modified,
+     not a copy."
+
+    scale isNil ifTrue:[
+	translation isNil ifTrue:[
+	    ^ p
+	].
+	^ p + translation
+    ].
+    translation isNil ifTrue:[
+	^ p * scale
+    ].
+    ^ (p * scale + translation)
+!
+
 compose:aTransformation 
     "return a new WindowingTransformation that is the
      composition of the receiver and aTransformation.
@@ -215,7 +389,7 @@
     |aTransformationScale newScale newTranslation|
 
     aTransformationScale := aTransformation scale.
-    scale == nil ifTrue:[
+    scale isNil ifTrue:[
 	aTransformation noScale ifTrue:[
 	    newScale := nil
 	] ifFalse:[
@@ -243,7 +417,7 @@
      This is a destructive operation, modifying the transformation
      represented by the receiver"
 
-    |newScale newTranslation|
+    |newScale|
 
     aScale isNil ifTrue:[^ self].
 
@@ -252,7 +426,9 @@
     ] ifFalse:[
 	newScale := scale * aScale
     ].
-    translation := translation * aScale.
+    translation notNil ifTrue:[
+	translation := translation * aScale.
+    ].
     scale := newScale.
 !
 
@@ -279,17 +455,19 @@
 
     |checkedScale newScale newTranslation|
 
-    aScale == nil ifTrue:[
+    aScale isNil ifTrue:[
 	newScale := scale.
 	newTranslation := translation
     ] ifFalse:[
 	checkedScale := self checkScale:aScale.
-	scale == nil ifTrue:[
+	scale isNil ifTrue:[
 	    newScale := checkedScale
 	] ifFalse:[
 	    newScale := scale * checkedScale
 	].
-	newTranslation := checkedScale * translation
+	translation notNil ifTrue:[
+	    newTranslation := checkedScale * translation
+	]
     ].
     ^ (self class) 
 	  scale:newScale
@@ -345,35 +523,50 @@
 scale:aScale translation:aTranslation
     "sets the scale to aScale and the translation to aTranslation."
 
-    scale := aScale asPoint.
-    translation := aTranslation asPoint
+    aScale isNil ifTrue:[
+	scale := aScale
+    ] ifFalse:[
+	scale := aScale asPoint.
+    ].
+    aTranslation isNil ifTrue:[
+	translation := aTranslation
+    ] ifFalse:[
+	translation := aTranslation asPoint
+    ]
 !
 
-translation:aValue
-    "Set the receiver's translation to aValue, a Point or Number."
+translation:aTranslation
+    "Set the receiver's translation to aTranslation, a Point or Number."
 
-    translation := aValue asPoint
+    aTranslation isNil ifTrue:[
+	translation := aTranslation
+    ] ifFalse:[
+	translation := aTranslation asPoint
+    ]
 !
 
-scale:aValue
-    "Set the receiver's scale to aValue, a Point or Number."
+scale:aScale
+    "Set the receiver's scale to aScale, a Point or Number."
 
-    scale := aValue asPoint
+    aScale isNil ifTrue:[
+	scale := aScale
+    ] ifFalse:[
+	scale := aScale asPoint.
+    ].
 !
 
 scale
     "return a copy of the Point that represents the
      current scale of the receiver."
 
-    scale == nil ifTrue:[
-	^ Point x:1 y:1
-    ].
+    scale isNil ifTrue:[^ (1@1) copy].
     ^ scale copy
 !
 
 translation
     "return a copy of the receiver's translation."
 
+    translation isNil ifTrue:[^ (0@0) copy].
     ^ translation copy
 !
 
@@ -397,7 +590,7 @@
 printOn:aStream
     aStream nextPutAll:self class name.
     aStream nextPutAll:' scale: '.
-    scale printOn:aStream
+    scale printOn:aStream.
     aStream nextPutAll:' translation: '.
     translation printOn:aStream
 ! !