1//
2//  PRCurvesPath.m
3//  PRICE
4//
5//  Created by Riccardo Mottola on Thu 11 August 2011.
6//  Copyright 2011-2014 Riccardo Mottola. All rights reserved.
7//
8// This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
9// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10
11#import "PRCurvesPath.h"
12#import <AppKit/NSColor.h>
13
14@implementation PRCurvesPath
15
16- (id)init
17{
18  self = [super init];
19  if(self)
20    {
21      isEditing = YES;
22    }
23  return self;
24}
25
26-(void)stroke
27{
28  unsigned i;
29
30  [super stroke];
31
32  if (isEditing)
33    for (i = 0; i < [self elementCount]; i++)
34      {
35	NSPoint cp[3];
36	NSBezierPathElement pe;
37	NSRect cpRect;
38
39	pe = [self elementAtIndex: i associatedPoints: cp];
40
41	if (pe == NSMoveToBezierPathElement)
42	  {
43	    [[NSColor purpleColor] set];
44	    cpRect = NSMakeRect(cp[0].x - 1, cp[0].y - 1, 4, 4);
45	    [NSBezierPath fillRect: cpRect];
46	  }
47	else if (pe == NSCurveToBezierPathElement)
48	  {
49	    [[NSColor orangeColor] set];
50	    cpRect = NSMakeRect(cp[0].x - 1, cp[0].y - 1, 4, 4);
51	    [NSBezierPath fillRect: cpRect];
52	    [[NSColor orangeColor] set];
53	    cpRect = NSMakeRect(cp[1].x - 1, cp[1].y - 1, 4, 4);
54	    [NSBezierPath fillRect: cpRect];
55	    [[NSColor purpleColor] set];
56	    cpRect = NSMakeRect(cp[2].x - 1, cp[2].y - 1, 4, 4);
57	    [NSBezierPath fillRect: cpRect];
58	  }
59
60      }
61
62}
63
64-(BOOL)isEditing;
65{
66  return isEditing;
67}
68
69-(void)setIsEditing: (BOOL)flag
70{
71  isEditing = flag;
72}
73
74-(NSPoint)blackPoint
75{
76  NSPoint cp[3];
77  NSPoint p;
78  NSBezierPathElement pe;
79
80  pe = [self elementAtIndex: 0 associatedPoints: cp];
81  p = cp[0];
82  NSLog(@"calculated black point: %f", p.x);
83  // ATTENTION: this is really true only for the simple S curve
84  return p;
85}
86
87-(NSPoint)whitePoint
88{
89  NSPoint cp[3];
90  NSPoint p;
91  NSBezierPathElement pe;
92
93  pe = [self elementAtIndex:[self elementCount]-1 associatedPoints: cp];
94  p = NSZeroPoint;
95  if (pe == NSMoveToBezierPathElement)
96    p = cp[0];
97  else if (pe == NSLineToBezierPathElement)
98    p = cp[0];
99  else if (pe == NSCurveToBezierPathElement)
100    p = cp[2];
101
102  NSLog(@"calculated white point: %f", p.x);
103  return p;
104}
105
106-(NSArray *)values
107{
108  NSBezierPath *tp;
109  NSBezierPath *fp;
110  unsigned i, j;
111  NSPoint *yVals;
112  unsigned valsCount;
113  NSMutableArray *f;
114  unsigned minX, maxX;
115  float lastY;
116
117
118  tp = [NSBezierPath bezierPath];
119  [tp appendBezierPath:(NSBezierPath *)self];
120  [tp setFlatness: 1.0];
121  fp = [tp bezierPathByFlatteningPath];
122
123  valsCount = [fp elementCount];
124  yVals = calloc(valsCount, sizeof(NSPoint));
125  if (yVals == NULL)
126    return nil;
127
128  f = [[NSMutableArray alloc] initWithCapacity: UCHAR_MAX];
129  for (i = 0; i < valsCount; i++)
130    {
131      NSBezierPathElement pe;
132      NSPoint cp[3];
133
134      pe = [fp elementAtIndex: i associatedPoints: cp];
135
136      yVals[i] = cp[0];
137    }
138
139  minX = floor(yVals[0].x);
140  maxX = floor(yVals[valsCount].x);
141
142  for (i = 0; i < minX; i++)
143    [f addObject: [NSNumber numberWithFloat: yVals[0].y]];
144
145
146  for (j = 0; j < valsCount; j++)
147    {
148      unsigned k, l;
149      float y1, y2;
150
151      /* find estimation interval (k) and begin/end values y1 y2 */
152      y1 = yVals[j].y;
153
154      l = i;
155      k = i;
156
157      if (j+1 < valsCount)
158	{
159  	  while (k < floor(yVals[j+1].x))
160	    k++;
161          y2 = yVals[j+1].y;
162	}
163      else
164	{
165	  y2 = y1;
166	  k++;
167	}
168
169//      NSLog(@"%d block %d-%d, y1-y2 %f-%f", j, l, k, y1, y2);
170      for (; i < k; i++)
171	{
172	  float a;
173
174	  a = (float)(i-l)/(k-l);
175//	  NSLog(@"a: %f", a);
176	  [f addObject: [NSNumber numberWithFloat: (y1 + (y2-y1)*a)]];
177	}
178    }
179
180  lastY = [[f objectAtIndex: [f count]-1] floatValue];
181
182  for (; i <= UCHAR_MAX; i++)
183    [f addObject: [NSNumber numberWithFloat: lastY]];
184
185  free(yVals);
186
187  return f;
188}
189
190-(void)move: (NSPoint)p1 toPoint:(NSPoint)p2
191{
192  unsigned i;
193  NSLog (@"move %f %f %f %f", p1.x, p1.y, p2.x, p2.y);
194  for (i = 0; i < [self elementCount]; i++)
195    {
196      NSPoint cp[3];
197      NSBezierPathElement pe;
198      NSRect cpRect;
199
200      pe = [self elementAtIndex: i associatedPoints: cp];
201      if (pe == NSMoveToBezierPathElement)
202        {
203          cpRect = NSMakeRect(cp[0].x - 1, cp[0].y - 1, 4, 4);
204          if (NSPointInRect(p1, cpRect))
205            {
206              cp[0] = p2;
207            }
208        }
209      else if (pe == NSCurveToBezierPathElement)
210        {
211          cpRect = NSMakeRect(cp[0].x - 1, cp[0].y - 1, 4, 4);
212          if(NSPointInRect(p1, cpRect))
213            cp[0] = p2;
214          cpRect = NSMakeRect(cp[1].x - 1, cp[1].y - 1, 4, 4);
215          if (NSPointInRect(p1, cpRect))
216            cp[1] = p2;
217          cpRect = NSMakeRect(cp[2].x - 1, cp[2].y - 1, 4, 4);
218          if(NSPointInRect(p1, cpRect))
219            cp[2] = p2;
220        }
221      [self setAssociatedPoints:cp atIndex:i];
222    }
223}
224
225-(BOOL)pointOnControlHandle:(NSPoint)p;
226{
227  unsigned i;
228  BOOL hit;
229
230  hit = NO;
231  for (i = 0; i < [self elementCount]; i++)
232    {
233      NSPoint cp[3];
234      NSBezierPathElement pe;
235      NSRect cpRect;
236
237      pe = [self elementAtIndex: i associatedPoints: cp];
238
239      if (pe == NSMoveToBezierPathElement)
240        {
241          cpRect = NSMakeRect(cp[0].x - 1, cp[0].y - 1, 4, 4);
242          hit |= NSPointInRect(p, cpRect);
243        }
244      else if (pe == NSCurveToBezierPathElement)
245        {
246          cpRect = NSMakeRect(cp[0].x - 1, cp[0].y - 1, 4, 4);
247          hit |= NSPointInRect(p, cpRect);
248          cpRect = NSMakeRect(cp[1].x - 1, cp[1].y - 1, 4, 4);
249          hit |= NSPointInRect(p, cpRect);
250          cpRect = NSMakeRect(cp[2].x - 1, cp[2].y - 1, 4, 4);
251          hit |= NSPointInRect(p, cpRect);
252        }
253    }
254  return hit;
255}
256
257
258@end
259