text: //
  //  GTMGeometryUtils.h
  //
  //  Utilities for geometrical utilities such as conversions
  //  between different types.
  //
  //  Copyright 2006-2008 Google Inc.
  //
  //  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  //  use this file except in compliance with the License.  You may obtain a copy
  //  of the License at
  //
  //  http://www.apache.org/licenses/LICENSE-2.0
  //
  //  Unless required by applicable law or agreed to in writing, software
  //  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  //  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
  //  License for the specific language governing permissions and limitations under
  //  the License.
  //
  
  #import <Foundation/Foundation.h>
  #import "GTMDefines.h"
  #if GTM_IPHONE_SDK
  #import <CoreGraphics/CoreGraphics.h>
  #endif //  GTM_IPHONE_SDK
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  enum {
    GTMScaleProportionally = 0,   // Fit proportionally
    GTMScaleToFit,                // Forced fit (distort if necessary)
    GTMScaleNone,                 // Don't scale (clip)
    GTMScaleToFillProportionally = 101  // Scale proportionally to fill area
  };
  typedef NSUInteger GTMScaling;
  
  enum {
    GTMRectAlignCenter = 0,
    GTMRectAlignTop,
    GTMRectAlignTopLeft,
    GTMRectAlignTopRight,
    GTMRectAlignLeft,
    GTMRectAlignBottom,
    GTMRectAlignBottomLeft,
    GTMRectAlignBottomRight,
    GTMRectAlignRight
  };
  typedef NSUInteger GTMRectAlignment;
  
  #pragma mark -
  #pragma mark CG - Point On Rect
  /// Return middle of min X side of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    point located in the middle of min X side of rect
  GTM_INLINE CGPoint GTMCGMidMinX(CGRect rect) {
    return CGPointMake(CGRectGetMinX(rect), CGRectGetMidY(rect));
  }
  
  /// Return middle of max X side of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    point located in the middle of max X side of rect
  GTM_INLINE CGPoint GTMCGMidMaxX(CGRect rect) {
    return CGPointMake(CGRectGetMaxX(rect), CGRectGetMidY(rect));
  }
  
  /// Return middle of max Y side of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    point located in the middle of max Y side of rect
  GTM_INLINE CGPoint GTMCGMidMaxY(CGRect rect) {
    return CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
  }
  
  /// Return middle of min Y side of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    point located in the middle of min Y side of rect
  GTM_INLINE CGPoint GTMCGMidMinY(CGRect rect) {
    return CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
  }
  
  /// Return center of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    point located in the center of rect
  GTM_INLINE CGPoint GTMCGCenter(CGRect rect) {
    return CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
  }
  
  #pragma mark -
  #pragma mark CG - Rect-Size Conversion
  
  /// Return size of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    size of rectangle
  GTM_INLINE CGSize GTMCGRectSize(CGRect rect) {
    return CGSizeMake(CGRectGetWidth(rect), CGRectGetHeight(rect));
  }
  
  /// Return rectangle of size
  //
  //  Args:
  //    size - size
  //
  //  Returns:
  //    rectangle of size (origin 0,0)
  GTM_INLINE CGRect GTMCGRectOfSize(CGSize size) {
    return CGRectMake(0.0f, 0.0f, size.width, size.height);
  }
  
  #pragma mark -
  #pragma mark CG - Rect Scaling and Alignment
  
  ///  Scales an CGRect
  //
  //  Args:
  //    inRect: Rect to scale
  //    xScale: fraction to scale (1.0 is 100%)
  //    yScale: fraction to scale (1.0 is 100%)
  //
  //  Returns:
  //    Converted Rect
  GTM_INLINE CGRect GTMCGRectScale(CGRect inRect, CGFloat xScale, CGFloat yScale) {
    return CGRectMake(inRect.origin.x, inRect.origin.y,
                      inRect.size.width * xScale, inRect.size.height * yScale);
  }
  
  
  /// Align rectangles
  //
  //  Args:
  //    alignee - rect to be aligned
  //    aligner - rect to be aligned from
  //    alignment - way to align the rectangles
  CGRect GTMCGAlignRectangles(CGRect alignee, CGRect aligner,
                              GTMRectAlignment alignment);
  /// Scale rectangle
  //
  //  Args:
  //    scalee - rect to be scaled
  //    size - size to scale to
  //    scaling - way to scale the rectangle
  CGRect GTMCGScaleRectangleToSize(CGRect scalee, CGSize size,
                                   GTMScaling scaling);
  
  #pragma mark -
  #pragma mark CG - Miscellaneous
  
  /// Calculate the distance between two points.
  //
  //  Args:
  //    pt1 first point
  //    pt2 second point
  //
  //  Returns:
  //    Distance
  GTM_INLINE CGFloat GTMCGDistanceBetweenPoints(CGPoint pt1, CGPoint pt2) {
    CGFloat dX = pt1.x - pt2.x;
    CGFloat dY = pt1.y - pt2.y;
  #if CGFLOAT_IS_DOUBLE
    return sqrt(dX * dX + dY * dY);
  #else
    return sqrtf(dX * dX + dY * dY);
  #endif
  }
  
  #if !GTM_IPHONE_SDK
  // iPhone does not have NSTypes defined, only CGTypes. So no NSRect, NSPoint etc.
  
  #pragma mark -
  #pragma mark NS <-> CG Rect Conversion
  
  ///  Convert from a NSRect to a CGRect.
  //
    ///  NSRect are relative to 0,0 in lower left;
  ///  CGRect are relative to 0,0 in lower left
  //
  //  Args:
  //    inRect: NSRect to convert
  //
  //  Returns:
  //    Converted CGRect
  GTM_INLINE CGRect GTMNSRectToCGRect(NSRect inRect) {
    CGRect cg = {
      .origin = {.x = inRect.origin.x, .y = inRect.origin.y},
      .size = {.width = inRect.size.width, .height = inRect.size.height}
    };
    return cg;
  }
  
  
  #pragma mark -
  #pragma mark NS <-> CG Size Conversion
  
  ///  Convert from a NSSize to a CGSize.
  //
  //  Args:
  //    inSize: NSSize to convert
  //
  //  Returns:
  //    Converted CGSize
  GTM_INLINE CGSize GTMNSSizeToCGSize(NSSize inSize) {
    CGSize cg = {.width = inSize.width, .height = inSize.height};
    return cg;
  }
  
  #pragma mark -
  #pragma mark NS - Point On Rect
  
  /// Return middle of min X side of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    point located in the middle of min X side of rect
  GTM_INLINE NSPoint GTMNSMidMinX(NSRect rect) {
    return NSMakePoint(NSMinX(rect), NSMidY(rect));
  }
  
  /// Return middle of max X side of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    point located in the middle of max X side of rect
  GTM_INLINE NSPoint GTMNSMidMaxX(NSRect rect) {
    return NSMakePoint(NSMaxX(rect), NSMidY(rect));
  }
  
  /// Return middle of max Y side of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    point located in the middle of max Y side of rect
  GTM_INLINE NSPoint GTMNSMidMaxY(NSRect rect) {
    return NSMakePoint(NSMidX(rect), NSMaxY(rect));
  }
  
  /// Return middle of min Y side of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    point located in the middle of min Y side of rect
  GTM_INLINE NSPoint GTMNSMidMinY(NSRect rect) {
    return NSMakePoint(NSMidX(rect), NSMinY(rect));
  }
  
  /// Return center of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    point located in the center of rect
  GTM_INLINE NSPoint GTMNSCenter(NSRect rect) {
    return NSMakePoint(NSMidX(rect), NSMidY(rect));
  }
  
  #pragma mark -
  #pragma mark NS - Rect-Size Conversion
  
  /// Return size of rectangle
  //
  //  Args:
  //    rect - rectangle
  //
  //  Returns:
  //    size of rectangle
  GTM_INLINE NSSize GTMNSRectSize(NSRect rect) {
    return NSMakeSize(NSWidth(rect), NSHeight(rect));
  }
  
  /// Return rectangle of size
  //
  //  Args:
  //    size - size
  //
  //  Returns:
  //    rectangle of size (origin 0,0)
  GTM_INLINE NSRect GTMNSRectOfSize(NSSize size) {
    return NSMakeRect(0.0f, 0.0f, size.width, size.height);
  }
  
  #pragma mark -
  #pragma mark NS - Rect Scaling and Alignment
  
  ///  Scales an NSRect
  //
  //  Args:
  //    inRect: Rect to scale
  //    xScale: fraction to scale (1.0 is 100%)
  //    yScale: fraction to scale (1.0 is 100%)
  //
  //  Returns:
  //    Converted Rect
  GTM_INLINE NSRect GTMNSRectScale(NSRect inRect, CGFloat xScale, CGFloat yScale) {
    return NSMakeRect(inRect.origin.x, inRect.origin.y,
                      inRect.size.width * xScale, inRect.size.height * yScale);
  }
  
  /// Align rectangles
  //
  //  Args:
  //    alignee - rect to be aligned
  //    aligner - rect to be aligned from
  GTM_INLINE NSRect GTMNSAlignRectangles(NSRect alignee, NSRect aligner,
                                         GTMRectAlignment alignment) {
    return NSRectFromCGRect(GTMCGAlignRectangles(GTMNSRectToCGRect(alignee),
                                                 GTMNSRectToCGRect(aligner),
                                                 alignment));
  }
  
  /// Align a rectangle to another
  //
  //  Args:
  //    scalee - rect to be scaled
  //    scaler - rect to scale to
  //    scaling - way to scale the rectangle
  //    alignment - way to align the scaled rectangle
  GTM_INLINE NSRect GTMNSScaleRectToRect(NSRect scalee,
                                         NSRect scaler,
                                         GTMScaling scaling,
                                         GTMRectAlignment alignment) {
  
    return NSRectFromCGRect(
             GTMCGAlignRectangles(
               GTMCGScaleRectangleToSize(GTMNSRectToCGRect(scalee),
                                         GTMNSSizeToCGSize(scaler.size),
                                         scaling),
               GTMNSRectToCGRect(scaler),
               alignment));
  }
  
  /// Scale rectangle
  //
  //  Args:
  //    scalee - rect to be scaled
  //    size - size to scale to
  //    scaling - way to scale the rectangle
  GTM_INLINE NSRect GTMNSScaleRectangleToSize(NSRect scalee, NSSize size,
                                              GTMScaling scaling) {
    return NSRectFromCGRect(GTMCGScaleRectangleToSize(GTMNSRectToCGRect(scalee),
                                                       GTMNSSizeToCGSize(size),
                                                       scaling));
  }
  
  #pragma mark -
  #pragma mark NS - Miscellaneous
  
  /// Calculate the distance between two points.
  //
  //  Args:
  //    pt1 first point
  //    pt2 second point
  //
  //  Returns:
  //    Distance
  GTM_INLINE CGFloat GTMNSDistanceBetweenPoints(NSPoint pt1, NSPoint pt2) {
    CGPoint cgpt1 = {.x = pt1.x, .y = pt1.y};
    CGPoint cgpt2 = {.x = pt2.x, .y = pt2.y};
    return GTMCGDistanceBetweenPoints(cgpt1, cgpt2);
  }
  
  #endif //  !GTM_IPHONE_SDK
  
  #ifdef __cplusplus
  }
  #endif
  