LineSegment.st
author Claus Gittinger <cg@exept.de>
Sat, 02 May 2020 21:40:13 +0200
changeset 5476 7355a4b11cb6
parent 2152 ad1307561fe5
permissions -rw-r--r--
#FEATURE by cg class: Socket class added: #newTCPclientToHost:port:domain:domainOrder:withTimeout: changed: #newTCPclientToHost:port:domain:withTimeout:

"
 COPYRIGHT (c) 1996 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.
"
"{ Package: 'stx:libbasic2' }"

Geometric subclass:#LineSegment
	instanceVariableNames:'startPoint endPoint'
	classVariableNames:''
	poolDictionaries:''
	category:'Graphics-Geometry-Objects'
!

!LineSegment class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1996 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.
"


!

documentation
"
    LineSegments represent a line consisting of start and endPoint
    (actually, its a vector, since the direction makes a difference when
     instances are compared using #=).

    [author:]
        Claus Gittinger

    [see also:]
        Rectangle Polygon EllipticalArc Circle Spline Curve 
        Point Arrow ArrowedSpline
        GraphicsContext
        StrokingWrapper
"

!

examples
"
  low leel use:
                                                                        [exBegin]
    |v l|

    v := (View extent:100@100) openAndWait.

    l := LineSegment from:10@10 to:90@90. 

    v paint:Color red.
    l displayStrokedOn:v.

    l setStart:90@10 end:10@90.
    v paint:Color blue.
    l displayStrokedOn:v.
                                                                        [exEnd]
  as component (automatic redraw):
                                                                        [exBegin]
    |v l|

    v := View extent:100@100.

    l := LineSegment from:10@10 to:90@90. 
    v addComponent:(StrokingWrapper on:l).

    l := LineSegment from:90@10 to:10@90. 
    v addComponent:((StrokingWrapper on:l) foregroundColor:(Color red)).

    v open.
                                                                        [exEnd]
"
! !

!LineSegment class methodsFor:'instance creation'!

from:start to:end
    "return a new lineSegment."

    ^ self new setStart:start end:end

    "Created: 8.5.1996 / 20:40:13 / cg"
!

with:p1 with:p2
    "return a new lineSegment; the smaller point is taken as startPoint."

    |l|

    l := self new.
    p1 < p2 ifTrue:[
        l setStart:p1 end:p2
    ] ifFalse:[
        l setStart:p2 end:p1
    ].
    ^ l.

    "Created: 8.5.1996 / 20:41:03 / cg"
! !

!LineSegment methodsFor:'accessing'!

end
    "return the endPoint"

    ^ endPoint

    "Created: 8.5.1996 / 20:41:43 / cg"
!

end:aPoint
    "set the endPoint"

    endPoint := aPoint

    "Created: 8.5.1996 / 20:41:54 / cg"
!

setStart:p1 end:p2
    "set both the startPoint and the endPoint"

    startPoint := p1.
    endPoint := p2.
!

start
    "return the startPoint"

    ^ startPoint

    "Created: 8.5.1996 / 20:41:35 / cg"
!

start:aPoint
    "set the startPoint"

    startPoint := aPoint

    "Created: 8.5.1996 / 20:42:07 / cg"
!

start:p1 end:p2
    <resource: #obsolete>
    "set both the startPoint and the endPoint.
     Obsolete - use setStart:end: for VW compatibility."

    self obsoleteMethodWarning:'use #setStart:end: for VW compatibility'.
    self setStart:p1 end:p2.
! !

!LineSegment methodsFor:'comparing'!

= aLineSegment
    "return true, if the receiver represents the same lineSegment
     as the argument, aLineSegment"

    aLineSegment species ~~ self species ifTrue:[^ false].
    ^ (startPoint = aLineSegment start
      and:[endPoint = aLineSegment end])

    "Created: 8.5.1996 / 22:13:02 / cg"
    "Modified: 8.5.1996 / 22:14:34 / cg"
!

hash
    "return a number useul for hashing.
     Redefined, since #= is redefined."

    ^ (startPoint hash bitShift:12) bitOr:(endPoint hash)

    "Modified: 8.5.1996 / 22:14:12 / cg"
! !

!LineSegment methodsFor:'converting'!

asPointArray
    "return an array containing my points."

    ^ Array with:startPoint with:endPoint

    "Created: 8.5.1996 / 20:46:08 / cg"
! !

!LineSegment methodsFor:'displaying'!

displayFilledOn:aGC
    "raise an error - a lineSegment cannot be drawn filled"

    self shouldNotImplement

    "Created: 8.5.1996 / 21:04:27 / cg"
!

displayStrokedOn:aGC
    "display the receiver in the graphicsContext, aGC"

    aGC displayLineFrom:startPoint to:endPoint

    "
     |v|

     v := View new openAndWait.

     (LineSegment from:10@10 to:50@50) displayStrokedOn:v
    "

    "Modified: 8.5.1996 / 14:40:53 / cg"
    "Created: 8.5.1996 / 21:05:16 / cg"
! !

!LineSegment methodsFor:'printing'!

printOn:aStream
    aStream nextPutAll:'LineSegment from:'.
    startPoint printOn:aStream.
    aStream nextPutAll:' to:'.
    endPoint printOn:aStream.
! !

!LineSegment methodsFor:'queries'!

angle
    "return the receiver's angle (in degrees) in a polar coordinate system.
     The angle is counted counter-clock-wise, starting with 0 for a horizontal
     line (i.e. 0@0 -> 100@0 has an angle of 0 and 0@0 -> 0@100 has an angle of 90)"

    ^ (endPoint - startPoint) degrees

    "
     (LineSegment from:0@0 to:100@0) angle
     (LineSegment from:0@0 to:100@100) angle   
     (LineSegment from:0@0 to:0@100) angle      
     (LineSegment from:0@0 to:-100@100) angle
     (LineSegment from:0@0 to:-100@0) angle
     (LineSegment from:0@0 to:-100@-100) angle
     (LineSegment from:0@0 to:0@-100) angle
    "
!

center
    ^ (startPoint + endPoint) / 2

    "
     (LineSegment from:(10@10) to:(20@10)) center  
     (LineSegment from:(10@10) to:(20@20)) center  
    "
!

computeBounds
    "return the smallest enclosing rectangle"

    |x y minX maxX minY maxY|

    minX := maxX := startPoint x.
    x := endPoint x.
    minX := minX min:x.
    maxX := maxX max:x.

    minY := maxY := startPoint y.
    y := endPoint y.
    minY := minY min:y.
    maxY := maxY max:y.

    ^ Rectangle left:minX right:maxX top:minY bottom:maxY

    "
     (LineSegment from:(10@10) to:(90@90)) bounds 
    "

    "Modified: 26.5.1996 / 13:06:55 / cg"
    "Created: 12.2.1997 / 11:43:50 / cg"
!

dist:aPoint
    "the distance of aPoint to this segment"

    |u v px py ax ay bx by|

    ax := startPoint x.
    ay := startPoint y.
    bx := endPoint x.
    by := endPoint y.
    px := aPoint x.
    py := aPoint y.

    u := aPoint - startPoint.
    v := endPoint - startPoint.
    ((u x * v x) + (u y * v y)) < 0 ifTrue:[
        ^ "(startPoint dist:aPoint)" (( px - ax) squared + (py - ay) squared) sqrt
    ].

    u := aPoint - endPoint.
    v := v negated.
    ((u x * v x) + (u y * v y)) < 0 ifTrue:[
        ^ "(endPoint dist:aPoint)" (( px - bx) squared + (py - by) squared) sqrt
    ].

    ^( (( px * ( ay - by )) + (py * ( bx - ax )) + ( (ax * by) - (bx * ay) ) ) 
     / ( ( bx - ax )squared + ( by - ay )squared ) sqrt ) abs

    "
     (LineSegment from:(0@0) to:(10@10)) dist:0@0      
     (LineSegment from:(0@0) to:(10@10)) dist:10@10    
     (LineSegment from:(0@0) to:(10@10)) dist:11@10    
     (LineSegment from:(0@0) to:(10@10)) dist:-1@-1    
     (LineSegment from:(0@0) to:(10@10)) dist:5@5      
     (LineSegment from:(0@0) to:(10@10)) dist:6@4      
     (LineSegment from:(0@0) to:(10@10)) dist:5@0      
    "
!

isHorizontal
    "return true, if I am a horizontal line"

    ^ startPoint y = endPoint y
!

isVertical
    "return true, if I am a vertical line"

    ^ startPoint x = endPoint x
!

length
    "return the length of the vector"

    ^ startPoint dist:endPoint
! !

!LineSegment methodsFor:'testing'!

isLineSegment
    "return true, if the receiver is a line segment"

    ^ true


! !

!LineSegment methodsFor:'transforming'!

scaledBy:amount
    ^ self species 
        from:(startPoint scaledBy:amount)
        to:(endPoint scaledBy:amount)
!

translatedBy:amount
    ^ self species 
        from:(startPoint translatedBy:amount)
        to:(endPoint translatedBy:amount)
! !

!LineSegment class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic2/LineSegment.st,v 1.21 2009-06-06 10:07:44 cg Exp $'
! !