LCOV - code coverage report
Current view: top level - Core - OOJoystickProfile.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 22 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOJoystickProfile.m
       4             : 
       5             : Oolite
       6             : Copyright (C) 2004-2013 Giles C Williams and contributors
       7             : 
       8             : This program is free software; you can redistribute it and/or
       9             : modify it under the terms of the GNU General Public License
      10             : as published by the Free Software Foundation; either version 2
      11             : of the License, or (at your option) any later version.
      12             : 
      13             : This program is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU General Public License for more details.
      17             : 
      18             : You should have received a copy of the GNU General Public License
      19             : along with this program; if not, write to the Free Software
      20             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      21             : MA 02110-1301, USA.
      22             : 
      23             : */
      24             : 
      25             : #import "OOJoystickManager.h"
      26             : #import "OOJoystickProfile.h"
      27             : #import "OOMaths.h"
      28             : #import "OOLoggingExtended.h"
      29             : #import "Universe.h"
      30             : 
      31           0 : #define SPLINE_POINT_MIN_SPACING 0.02
      32             : 
      33           0 : @interface OOJoystickSplineSegment: NSObject <NSCopying>
      34             : {
      35             : @private
      36             :         double start;
      37           0 :         double end;
      38           0 :         double a[4];
      39           0 : }
      40             : 
      41             : - (id) init;
      42           0 : 
      43             : // Linear spline from left point to right point.  Returns nil if right.x - left.x <= 0.0.
      44             : - (id) initWithData: (NSPoint) left right: (NSPoint) right;
      45           0 : 
      46             : // Quadratic spline from left point to right point, with gradient specified at left.  returns nil if right.x - left.x <= 0.0.
      47             : - (id) initWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft;
      48           0 : 
      49             : // Quadratic spline from left point to right point, with gradient specified at right.  returns nil if right.x - left.x <= 0.0.
      50             : - (id) initWithData: (NSPoint) left right: (NSPoint) right gradientright: (double) gradientright;
      51           0 : 
      52             : // Cubic spline from left point to right point, with gradients specified at end points.  returns nil if right.x - left.x <= 0.0.
      53             : - (id) initWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft gradientright: (double) gradientright;
      54           0 : 
      55             : // Linear spline from left point to right point.  Returns nil if right.x - left.x <= 0.0.
      56             : + (id) segmentWithData: (NSPoint) left right: (NSPoint) right;
      57           0 : 
      58             : // Quadratic spline from left point to right point, with gradient specified at left.  returns nil if right.x - left.x <= 0.0.
      59             : + (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft;
      60           0 : 
      61             : // Quadratic spline from left point to right point, with gradient specified at right.  returns nil if right.x - left.x <= 0.0.
      62             : + (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientright: (double) gradientright;
      63           0 : 
      64             : // Cubic spline from left point to right point, with gradients specified at end points.  returns nil if right.x - left.x <= 0.0.
      65             : + (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft gradientright: (double) gradientright;
      66           0 : 
      67             : - (id) copyWithZone: (NSZone *) zone;
      68           0 : - (double) start;
      69           0 : - (double) end;
      70           0 : - (double) value: (double) t;
      71           0 : - (double) gradient: (double) t;
      72           0 : 
      73             : @end
      74             : 
      75             : @interface OOJoystickSplineAxisProfile (Private)
      76             : 
      77             : // Create the segments from the control points.  If there's a problem, e.g. control points not in order or overlapping,
      78             : // leave segments as they are and return NO.  Otherwise return YES.
      79             : - (BOOL) makeSegments;
      80           0 : 
      81             : @end
      82             : 
      83             : 
      84             : @implementation OOJoystickAxisProfile
      85             : 
      86             : - (id) init
      87             : {
      88             :         if ((self = [super init]))
      89             :         {
      90             :                 deadzone = STICK_DEADZONE;
      91             :         }
      92             :         return self;
      93             : }
      94             : 
      95             : - (id) copyWithZone: (NSZone *) zone
      96             : {
      97             :         OOJoystickAxisProfile *copy = [[[self class] alloc] init];
      98             :         return copy;
      99             : }
     100             : 
     101             : 
     102             : - (double) rawValue: (double) x
     103             : {
     104             :         return x;
     105             : }
     106             : 
     107             : - (double) value: (double) x
     108             : {
     109             :         if (fabs(x) < deadzone)
     110             :         {
     111             :                 return 0.0;
     112             :         }
     113             :         return x < 0 ? -[self rawValue: (-x-deadzone)/(1.0-deadzone)] : [self rawValue: (x-deadzone)/(1.0-deadzone)];
     114             : }
     115             : 
     116             : - (double) deadzone
     117             : {
     118             :         return deadzone;
     119             : }
     120             : 
     121             : - (void) setDeadzone: (double) newValue
     122             : {
     123             :         deadzone = OOClamp_0_max_d(newValue, STICK_MAX_DEADZONE);
     124             : }
     125             : 
     126             : @end
     127             : 
     128             : @implementation OOJoystickStandardAxisProfile
     129             : 
     130             : - (id) init
     131             : {
     132             :         if ((self = [super init]))
     133             :         {
     134             :                 power = 1.0;
     135             :                 parameter = 1.0;
     136             :         }
     137             :         return self;
     138             : }
     139             : 
     140             : - (id) copyWithZone: (NSZone *) zone
     141             : {
     142             :         OOJoystickStandardAxisProfile *copy = [[[self class] alloc] init];
     143             :         copy->power = power;
     144             :         copy->parameter = parameter;
     145             :         return copy;
     146             : }
     147             : 
     148             : - (void) setPower: (double) newValue
     149             : {
     150             :         if (newValue < 1.0)
     151             :         {
     152             :                 power = 1.0;
     153             :         }
     154             :         else if (newValue > STICKPROFILE_MAX_POWER)
     155             :         {
     156             :                 power = STICKPROFILE_MAX_POWER;
     157             :         }
     158             :         else
     159             :         {
     160             :                 power = newValue;
     161             :         }
     162             :         return;
     163             : }
     164             : 
     165             : - (double) power
     166             : {
     167             :         return power;
     168             : }
     169             : 
     170             : 
     171             : - (void) setParameter: (double) newValue
     172             : {
     173             :         parameter = OOClamp_0_1_d(newValue);
     174             :         return;
     175             : }
     176             : 
     177             : - (double) parameter
     178             : {
     179             :         return parameter;
     180             : }
     181             : 
     182             : 
     183             : - (double) rawValue: (double) x
     184             : {
     185             :         if (x < 0)
     186             :         {
     187             :                 return -OOClamp_0_1_d(parameter * pow(-x,power)-(parameter - 1.0)*(-x));
     188             :         }
     189             :         return OOClamp_0_1_d(parameter * pow(x,power)-(parameter - 1.0)*(x));
     190             : }
     191             : 
     192             : @end
     193             : 
     194             : @implementation OOJoystickSplineSegment
     195             : 
     196             : - (id) init
     197             : {
     198             :         if ((self = [super init]))
     199             :         {
     200             :                 start = 0.0;
     201             :                 end = 1.0;
     202             :                 a[0] = 0.0;
     203             :                 a[1] = 1.0;
     204             :                 a[2] = 0.0;
     205             :                 a[3] = 0.0;
     206             :         }
     207             :         return self;
     208             : }
     209             : 
     210             : - (id) copyWithZone: (NSZone *) zone
     211             : {
     212             :         OOJoystickSplineSegment *copy = [[OOJoystickSplineSegment allocWithZone: zone] init];
     213             :         copy->start = start;
     214             :         copy->end = end;
     215             :         copy->a[0] = a[0];
     216             :         copy->a[1] = a[1];
     217             :         copy->a[2] = a[2];
     218             :         copy->a[3] = a[3];
     219             :         return copy;
     220             : }
     221             : 
     222             : - (id) initWithData: (NSPoint) left right: (NSPoint) right
     223             : {
     224             :         double dx = right.x - left.x;
     225             :         if (dx <= 0.0)
     226             :         {
     227             :                 return nil;
     228             :         }
     229             :         if ((self = [super init]))
     230             :         {
     231             :                 start = left.x;
     232             :                 end = right.x;
     233             :                 a[1] = (right.y - left.y)/dx;
     234             :                 a[0] = left.y-a[1]*left.x;
     235             :                 a[2] = 0.0;
     236             :                 a[3] = 0.0;
     237             :         }
     238             :         return self;
     239             : }
     240             : 
     241             : - (id) initWithData:(NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft
     242             : {
     243             :         double dx = right.x - left.x;
     244             :         if (dx <= 0.0)
     245             :         {
     246             :                 return nil;
     247             :         }
     248             :         if ((self = [super init]))
     249             :         {
     250             :                 start = left.x;
     251             :                 end = right.x;
     252             :                 a[0] = left.y*right.x*(right.x - 2*left.x)/(dx*dx) + right.y*left.x*left.x/(dx*dx) - gradientleft*left.x*right.x/dx;
     253             :                 a[1] = 2*left.x*(left.y-right.y)/(dx*dx) + gradientleft*(left.x+right.x)/dx;
     254             :                 a[2] = (right.y-left.y)/(dx*dx) - gradientleft/dx;
     255             :         }
     256             :         return self;
     257             : }
     258             : 
     259             : - (id) initWithData: (NSPoint) left right: (NSPoint) right gradientright: (double) gradientright
     260             : {
     261             :         double dx = right.x - left.x;
     262             :         if (dx <= 0.0)
     263             :         {
     264             :                 return nil;
     265             :         }
     266             :         if ((self = [super init]))
     267             :         {
     268             :                 start = left.x;
     269             :                 end = right.x;
     270             :                 a[0] = (left.y*right.x*right.x + right.y*left.x*(left.x-2*right.x))/(dx*dx) + gradientright*left.x*right.x/dx;
     271             :                 a[1] = 2*right.x*(right.y-left.y)/(dx*dx) - gradientright*(left.x+right.x)/dx;
     272             :                 a[2] = (left.y-right.y)/(dx*dx) + gradientright/dx;
     273             :         }
     274             :         return self;
     275             : }
     276             : 
     277             : - (id) initWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft gradientright: (double) gradientright
     278             : {
     279             :         double dx = right.x - left.x;
     280             :         if (dx <= 0.0)
     281             :         {
     282             :                 return nil;
     283             :         }
     284             :         if ((self = [super init]))
     285             :         {
     286             :                 start = left.x;
     287             :                 end = right.x;
     288             :                 a[0] = (left.y*right.x*right.x*(right.x-3*left.x) - right.y*left.x*left.x*(left.x-3*right.x))/(dx*dx*dx) - (gradientleft*right.x + gradientright*left.x)*left.x*right.x/(dx*dx);
     289             :                 a[1] = 6*left.x*right.x*(left.y-right.y)/(dx*dx*dx) + (gradientleft*right.x*(right.x+2*left.x) + gradientright*left.x*(left.x+2*right.x))/(dx*dx);
     290             :                 a[2] = 3*(left.x+right.x)*(right.y-left.y)/(dx*dx*dx) - (gradientleft*(2*right.x+left.x)+gradientright*(2*left.x+right.x))/(dx*dx);
     291             :                 a[3] = 2*(left.y-right.y)/(dx*dx*dx) + (gradientleft+gradientright)/(dx*dx);
     292             :         }
     293             :         return self;
     294             : }
     295             : 
     296             : + (id) segmentWithData: (NSPoint) left right: (NSPoint) right
     297             : {
     298             :         OOJoystickSplineSegment *segment = [[OOJoystickSplineSegment alloc] initWithData: left right:right];
     299             :         return [segment autorelease];
     300             : }
     301             : 
     302             : 
     303             : + (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft
     304             : {
     305             :         OOJoystickSplineSegment *segment = [[OOJoystickSplineSegment alloc] initWithData: left right:right gradientleft:gradientleft];
     306             :         return [segment autorelease];
     307             : }
     308             : 
     309             : 
     310             : + (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientright: (double) gradientright
     311             : {
     312             :         OOJoystickSplineSegment *segment = [[OOJoystickSplineSegment alloc] initWithData: left right:right gradientright:gradientright];
     313             :         return [segment autorelease];
     314             : }
     315             : 
     316             : 
     317             : + (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft gradientright: (double) gradientright
     318             : {
     319             :         OOJoystickSplineSegment *segment = [[OOJoystickSplineSegment alloc] initWithData: left right:right gradientleft:gradientleft gradientright:gradientright];
     320             :         return [segment autorelease];
     321             : }
     322             : 
     323             : - (double) start
     324             : {
     325             :         return start;
     326             : }
     327             : 
     328             : 
     329             : - (double) end
     330             : {
     331             :         return end;
     332             : }
     333             : 
     334             : 
     335             : - (double) value: (double) x
     336             : {
     337             :         return a[0] + (a[1] + (a[2] + a[3]*x)*x)*x;
     338             : }
     339             : 
     340             : - (double) gradient: (double) x
     341             : {
     342             :         return a[1]+(2*a[2] + 3*a[3]*x)*x;
     343             : }
     344             : 
     345             : @end
     346             : 
     347             : 
     348             : @implementation OOJoystickSplineAxisProfile
     349             : 
     350             : - (id) init
     351             : {
     352             :         if ((self = [super init]))
     353             :         {
     354             :                 controlPoints = [[NSMutableArray alloc] initWithCapacity: 2];
     355             :                 segments = nil;
     356             :                 [self makeSegments];
     357             :         }
     358             :         return self;
     359             : }
     360             : 
     361             : - (void) dealloc
     362             : {
     363             :         [controlPoints release];
     364             :         [segments release];
     365             :         [super dealloc];
     366             :         return;
     367             : }
     368             : 
     369             : - (id) copyWithZone: (NSZone *) zone
     370             : {
     371             :         OOJoystickSplineAxisProfile *copy = [[[self class] alloc] init];
     372             :         copy->controlPoints = [controlPoints copyWithZone: zone];
     373             :         copy->segments = [segments copyWithZone: zone];
     374             :         return copy;
     375             : }
     376             : 
     377             : 
     378             : - (int) addControl: (NSPoint) point
     379             : {
     380             :         NSPoint left, right;
     381             :         NSUInteger i;
     382             : 
     383             :         if (point.x <= SPLINE_POINT_MIN_SPACING || point.x >= 1 - SPLINE_POINT_MIN_SPACING )
     384             :         {
     385             :                 return -1;
     386             :         }
     387             : 
     388             :         left.x = 0.0;
     389             :         left.y = 0.0;
     390             :         for (i = 0; i <= [controlPoints count]; i++ )
     391             :         {
     392             :                 if (i < [controlPoints count])
     393             :                 {
     394             :                         right = [[controlPoints objectAtIndex: i] pointValue];
     395             :                 }
     396             :                 else
     397             :                 {
     398             :                         right = NSMakePoint(1.0,1.0);
     399             :                 }
     400             :                 if ((point.x - left.x) < SPLINE_POINT_MIN_SPACING)
     401             :                 {
     402             :                         if (i == 0)
     403             :                         {
     404             :                                 return -1;
     405             :                         }
     406             :                         [controlPoints replaceObjectAtIndex: i - 1 withObject: [NSValue valueWithPoint: point]];
     407             :                         [self makeSegments];
     408             :                         return i - 1;
     409             :                 }
     410             :                 if ((right.x - point.x) >= SPLINE_POINT_MIN_SPACING)
     411             :                 {
     412             :                         [controlPoints insertObject: [NSValue valueWithPoint: point] atIndex: i];
     413             :                         [self makeSegments];
     414             :                         return i;
     415             :                 }
     416             :                 left = right;
     417             :         }
     418             :         return -1;
     419             : }
     420             : 
     421             : - (NSPoint) pointAtIndex: (NSInteger) index
     422             : {
     423             :         NSPoint point;
     424             :         if (index < 0)
     425             :         {
     426             :                 point.x = 0.0;
     427             :                 point.y = 0.0;
     428             :         }
     429             :         else if (index >= (NSInteger)[controlPoints count])
     430             :         {
     431             :                 point.x = 1.0;
     432             :                 point.y = 1.0;
     433             :         }
     434             :         else
     435             :         {
     436             :                 point = [[controlPoints objectAtIndex: index] pointValue];
     437             :         }
     438             :         return point;
     439             : }
     440             : 
     441             : - (int) countPoints
     442             : {
     443             :         return [controlPoints count];
     444             : }
     445             : 
     446             : 
     447             : - (NSArray *) controlPoints
     448             : {
     449             :         return [NSArray arrayWithArray: controlPoints];
     450             : }
     451             : 
     452             : // Calculate segments from control points
     453             : - (BOOL) makeSegments
     454           0 : {
     455             :         NSUInteger i;
     456             :         NSPoint left, right, next;
     457             :         double gradientleft, gradientright;
     458             :         OOJoystickSplineSegment* segment;
     459             :         BOOL first_segment = YES;
     460             :         NSMutableArray *new_segments = [NSMutableArray arrayWithCapacity: ([controlPoints count] + 1)];
     461             : 
     462             :         left.x = 0.0;
     463             :         left.y = 0.0;
     464             :         if ([controlPoints count] == 0)
     465             :         {
     466             :                 right.x = 1.0;
     467             :                 right.y = 1.0;
     468             :                 segment = [OOJoystickSplineSegment segmentWithData: left right: right];
     469             :                 [new_segments addObject:segment];
     470             :         }
     471             :         else
     472             :         {
     473             :                 gradientleft = 1.0;
     474             :                 right = [[controlPoints objectAtIndex: 0] pointValue];
     475             :                 for (i = 0; i < [controlPoints count]; i++)
     476             :                 {
     477             :                         next = [self pointAtIndex: i + 1];
     478             :                         if (next.x - left.x > 0.0)
     479             :                         {
     480             :                                 // we make the gradient at right equal to the gradient of a straight line between the neighcouring points
     481             :                                 gradientright = (next.y - left.y)/(next.x - left.x);
     482             :                                 if (first_segment)
     483             :                                 {
     484             :                                         segment = [OOJoystickSplineSegment segmentWithData: left right: right gradientright: gradientright];
     485             :                                 }
     486             :                                 else
     487             :                                 {
     488             :                                         segment = [OOJoystickSplineSegment segmentWithData: left right: right gradientleft: gradientleft gradientright: gradientright];
     489             :                                 }
     490             :                                 if (segment == nil)
     491             :                                 {
     492             :                                         return NO;
     493             :                                 }
     494             :                                 else
     495             :                                 {
     496             :                                         [new_segments addObject: segment];
     497             :                                         gradientleft = gradientright;
     498             :                                         first_segment = NO;
     499             :                                         left = right;
     500             :                                 }
     501             :                         }
     502             :                         right = next;
     503             :                 }
     504             :                 right.x = 1.0;
     505             :                 right.y = 1.0;
     506             :                 segment = [OOJoystickSplineSegment segmentWithData: left right: right gradientleft: gradientleft];
     507             :                 if (segment == nil)
     508             :                 {
     509             :                         return NO;
     510             :                 }
     511             :                 [new_segments addObject: segment];
     512             :         }
     513             :         [segments release];
     514             :         segments = [[NSArray arrayWithArray: new_segments] retain];
     515             :         return YES;
     516             : }
     517             : 
     518             : - (void) removeControl: (NSInteger) index
     519             : {
     520             :         if (index >= 0 && index < (NSInteger)[controlPoints count])
     521             :         {
     522             :                 [controlPoints removeObjectAtIndex: index];
     523             :                 [self makeSegments];
     524             :         }
     525             :         return;
     526             : }
     527             : 
     528             : - (void) clearControlPoints
     529             : {
     530             :         [controlPoints removeAllObjects];
     531             :         [self makeSegments];
     532             : }
     533             : 
     534             : - (void) moveControl: (NSInteger) index point: (NSPoint) point
     535             : {
     536             :         NSPoint left, right;
     537             : 
     538             :         point.x = OOClamp_0_1_d(point.x);
     539             :         point.y = OOClamp_0_1_d(point.y);
     540             :         if (index < 0 || index >= (NSInteger)[controlPoints count])
     541             :         {
     542             :                 return;
     543             :         }
     544             :         if (index == 0)
     545             :         {
     546             :                 left.x = 0.0;
     547             :                 right.x = 0.0;
     548             :         }
     549             :         else
     550             :         {
     551             :                 left = [[controlPoints objectAtIndex: (index-1)] pointValue];
     552             :         }
     553             :         if (index == (NSInteger)[controlPoints count] - 1)
     554             :         {
     555             :                 right.x = 1.0;
     556             :                 right.y = 1.0;
     557             :         }
     558             :         else
     559             :         {
     560             :                 right = [[controlPoints objectAtIndex: (index+1)] pointValue];
     561             :         }
     562             :         // preserve order of control points - if we attempt to move this control point beyond
     563             :         // either of its neighbours, move it back inside.  Also keep neighbours a distance of at least SPLINE_POINT_MIN_SPACING apart
     564             :         if (point.x - left.x < SPLINE_POINT_MIN_SPACING)
     565             :         {
     566             :                 point.x = left.x + SPLINE_POINT_MIN_SPACING;
     567             :                 if (right.x - point.x < SPLINE_POINT_MIN_SPACING)
     568             :                 {
     569             :                         point.x = (left.x + right.x)/2;
     570             :                 }
     571             :         }
     572             :         else if (right.x - point.x < SPLINE_POINT_MIN_SPACING)
     573             :         {
     574             :                 point.x = right.x - SPLINE_POINT_MIN_SPACING;
     575             :                 if (point.x - left.x < SPLINE_POINT_MIN_SPACING)
     576             :                 {
     577             :                         point.x = (left.x + right.x)/2;
     578             :                 }
     579             :         }
     580             :         [controlPoints replaceObjectAtIndex: index withObject: [NSValue valueWithPoint: point]];
     581             :         [self makeSegments];
     582             :         return;
     583             : }
     584             : 
     585             : - (double) rawValue: (double) x
     586             : {
     587             :         NSUInteger i;
     588             :         OOJoystickSplineSegment *segment;
     589             :         double sign;
     590             :         
     591             :         if (x < 0)
     592             :         {
     593             :                 sign = -1.0;
     594             :                 x = -x;
     595             :         }
     596             :         else
     597             :         {
     598             :                 sign = 1.0;
     599             :         }
     600             :         for (i = 0; i < [segments count]; i++)
     601             :         {
     602             :                 segment = [segments objectAtIndex: i];
     603             :                 if ([segment end] > x)
     604             :                 {
     605             :                         return sign * OOClamp_0_1_d([segment value:x]);
     606             :                 }
     607             :         }
     608             :         return 1.0;
     609             : }
     610             : 
     611             : - (double) gradient: (double) x
     612             : {
     613             :         NSUInteger i;
     614             :         OOJoystickSplineSegment *segment;
     615             :         for (i = 0; i < [segments count]; i++)
     616             :         {
     617             :                 segment = [segments objectAtIndex: i];
     618             :                 if ([segment end] > x)
     619             :                 {
     620             :                         return [segment gradient:x];
     621             :                 }
     622             :         }
     623             :         return 1.0;
     624             : }
     625             : 
     626             : 
     627             : @end
     628             : 

Generated by: LCOV version 1.14