// MorphLine.m
//
// created by Martin Wennerberg on Sun 12-Nov-1995
//
// when		who	modification

#import "MorphLine.h"
#import "algebra.h"

@implementation MorphLine

- init
{
    self = [super init];
    nPoints = 2;
    startPoints = NSZoneCalloc([self zone], nPoints, sizeof(NSPoint));
    endPoints = NSZoneCalloc([self zone], nPoints, sizeof(NSPoint));
    moveStartDelta     = 0.0;
    moveEndDelta       = 1.0;
    dissolveStartDelta = 0.0;
    dissolveEndDelta   = 1.0;

    return self;
}

- initWithValuesInDict:(NSDictionary *)dict
{
    NSArray	*startPointsValues;
    NSArray	*endPointsValues;
    NSNumber	*number;

    self = [self init];
    if ([dict isKindOfClass:[NSString class]])
        dict = [(NSString *)dict propertyList];

    startPointsValues = [dict objectForKey:MLKEY_STARTPOINTS];
    endPointsValues = [dict objectForKey:MLKEY_ENDPOINTS];
    if (MIN([startPointsValues count], [endPointsValues count]) >= 2)
      {
        unsigned	 i;

        nPoints = MIN([startPointsValues count], [endPointsValues count]);
        free (startPoints);
        free (endPoints);
        startPoints = NSZoneCalloc([self zone], nPoints, sizeof(NSPoint));
        endPoints = NSZoneCalloc([self zone], nPoints, sizeof(NSPoint));
        for (i = 0; i < nPoints; ++i)
          {
            startPoints[i] = NSPointFromString([startPointsValues objectAtIndex:i]);
            endPoints[i] = NSPointFromString([endPointsValues objectAtIndex:i]);
          }
      }
    number = [dict objectForKey:MLKEY_MOVESTART];
    if (number != nil)
        [self setMoveStartDelta:[number floatValue]];

    number = [dict objectForKey:MLKEY_MOVEEND];
    if (number != nil)
        [self setMoveEndDelta:[number floatValue]];

    number = [dict objectForKey:MLKEY_DISSOLVESTART];
    if (number != nil)
        [self setDissolveStartDelta:[number floatValue]];

    number = [dict objectForKey:MLKEY_DISSOLVEEND];
    if (number != nil)
        [self setDissolveEndDelta:[number floatValue]];

    return self;
}

- (NSDictionary *)pList
{
    NSMutableDictionary	*dict;
    NSMutableArray	*startPointStrings;
    NSMutableArray	*endPointStrings;
    unsigned		 i;

    dict = [NSMutableDictionary dictionaryWithCapacity:10];
    startPointStrings = [NSMutableArray arrayWithCapacity:nPoints];
    endPointStrings = [NSMutableArray arrayWithCapacity:nPoints];

    for (i = 0; i < nPoints; ++i)
      {
        [startPointStrings addObject:NSStringFromPoint(startPoints[i])];
        [endPointStrings addObject:NSStringFromPoint(endPoints[i])];
      }

    [dict setObject:startPointStrings forKey:MLKEY_STARTPOINTS];
    [dict setObject:endPointStrings forKey:MLKEY_ENDPOINTS];
    [dict setObject:[[NSNumber numberWithFloat:[self moveStartDelta]] description] forKey:MLKEY_MOVESTART];
    [dict setObject:[[NSNumber numberWithFloat:[self moveEndDelta]] description] forKey:MLKEY_MOVEEND];
    [dict setObject:[[NSNumber numberWithFloat:[self dissolveStartDelta]] description] forKey:MLKEY_DISSOLVESTART];
    [dict setObject:[[NSNumber numberWithFloat:[self dissolveEndDelta]] description] forKey:MLKEY_DISSOLVEEND];

    return dict;
}

- (id) copyWithZone:(NSZone *)zone
{
    MorphLine		*newObject;
    NSDictionary	*dict;

    dict = [self pList];
    newObject = [[[self class] allocWithZone:zone] initWithValuesInDict:dict];
    return newObject;
}

- (void) dealloc
{
    free (startPoints);
    free (endPoints);
    [super dealloc];
}

- (NSPoint) startPointAtDelta:(float)d
{
    if (d <= moveStartDelta || (moveEndDelta - moveStartDelta < 0.00001))
        return startPoints[0];
    if (d >= moveEndDelta)
        return startPoints[1];
    return pt_wmean (startPoints[0], startPoints[1], (d - moveStartDelta) / (moveEndDelta - moveStartDelta));
}

- (NSPoint) endPointAtDelta:(float)d
{
    if (d <= moveStartDelta || (moveEndDelta - moveStartDelta < 0.00001))
        return endPoints[0];
    if (d >= moveEndDelta)
        return endPoints[1];
    return pt_wmean (endPoints[0], endPoints[1], (d - moveStartDelta) / (moveEndDelta - moveStartDelta));
}

// The following two methods for controlling the coordinates currently
// only works when you have only two deltas (0 and 1). This can
// be modified to handle any number of points.
- (void) setStartPoint:(NSPoint)aPoint atDelta:(float)delta
{
    if (delta < 0.5)
        startPoints[0] = aPoint;
    else
        startPoints[1] = aPoint;
}

- (void) setEndPoint:(NSPoint)aPoint atDelta:(float)delta
{
    if (delta < 0.5)
        endPoints[0] = aPoint;
    else
        endPoints[1] = aPoint;
}


/****************************************************************
* Morph Controlls
****************************************************************/

- (void) setMoveStartDelta:(float)a
{
    moveStartDelta = a;
    moveEndDelta = MAX (moveStartDelta, moveEndDelta);
}

- (void) setMoveEndDelta:(float)a
{
    moveEndDelta = a;
    moveStartDelta = MIN (moveStartDelta, moveEndDelta);
}

- (void) setDissolveStartDelta:(float)a
{
    dissolveStartDelta = a;
    dissolveEndDelta = MAX (dissolveStartDelta, dissolveEndDelta);
}

- (void) setDissolveEndDelta:(float)a
{
    dissolveEndDelta = a;
    dissolveStartDelta = MIN (dissolveStartDelta, dissolveEndDelta);
}

- (float) moveStartDelta
{
    return moveStartDelta;
}

- (float) moveEndDelta
{
    return moveEndDelta;
}

- (float) dissolveStartDelta
{
    return dissolveStartDelta;
}

- (float) dissolveEndDelta
{
    return dissolveEndDelta;
}

/****************************************************************
* maths												
****************************************************************/
- (NSAffineTransform *) transformFromDelta:(float) beforeDelta
                                   toDelta:(float) afterDelta
// This method contains bugs that makes unusable. It would be nice to have, so I might fix it some day.
// A messy, but working implementation of the transformation mathemathics can be found in Morphed.m
{
    NSPoint	s0, s1, e0, e1;		// Start and end point coordinates of the lines 0 and 1
    NSAffineTransform	*t;
    double				scale;

    t = [NSAffineTransform transform];
    
    s0 = [self startPointAtDelta:beforeDelta];
    e0 = [self endPointAtDelta:beforeDelta];
    s1 = [self startPointAtDelta:afterDelta];
    e1 = [self endPointAtDelta:afterDelta];

    scale  = pt_dist(e1, s1) / pt_dist(e0, s0);
    
    [t translateXBy:-s0.x yBy:-s0.y];
    [t rotateByRadians:- line_angle(s0, e0)];
    [t scaleXBy:scale yBy:1.0];
    [t rotateByRadians:line_angle(s1, e1)];
    [t translateXBy:s1.x yBy:s1.y];
        
    return t;
}

/****************************************************************
* description												
****************************************************************/
- (NSString *) description
{
    return [[self pList] description];
}

/****************************************************************
* display
****************************************************************/
- (void) drawInView:(NSView *)view delta:(float)delta
{
    NSPoint	startPt, endPt;

    startPt = [self startPointAtDelta:delta];
    endPt = [self endPointAtDelta:delta];
    PSmoveto (startPt.x, startPt.y);
    PSlineto (endPt.x, endPt.y);
    PSstroke();
}

- (BOOL) hitTest:(NSPoint) aPoint
{
    return NO;
}
- (int) hitKnobTest: (NSPoint) aPoint
{
    return NO;
}

@end
