vn-verdnaturachat/ios/Pods/RSKImageCropper/RSKImageCropper/CGGeometry+RSKImageCropper.m

204 lines
7.0 KiB
Objective-C

//
// CGGeometry+RSKImageCropper.m
//
// Copyright (c) 2015 Ruslan Skorb, http://ruslanskorb.com/
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "CGGeometry+RSKImageCropper.h"
// K is a constant such that the accumulated error of our floating-point computations is definitely bounded by K units in the last place.
#ifdef CGFLOAT_IS_DOUBLE
static const CGFloat kK = 9;
#else
static const CGFloat kK = 0;
#endif
const CGPoint RSKPointNull = { INFINITY, INFINITY };
CGPoint RSKRectCenterPoint(CGRect rect)
{
return CGPointMake(CGRectGetMinX(rect) + CGRectGetWidth(rect) / 2,
CGRectGetMinY(rect) + CGRectGetHeight(rect) / 2);
}
CGRect RSKRectNormalize(CGRect rect)
{
CGPoint origin = rect.origin;
CGFloat x = origin.x;
CGFloat y = origin.y;
CGFloat ceilX = ceil(x);
CGFloat ceilY = ceil(y);
if (fabs(ceilX - x) < pow(10, kK) * RSK_EPSILON * fabs(ceilX + x) || fabs(ceilX - x) < RSK_MIN ||
fabs(ceilY - y) < pow(10, kK) * RSK_EPSILON * fabs(ceilY + y) || fabs(ceilY - y) < RSK_MIN) {
origin.x = ceilX;
origin.y = ceilY;
} else {
origin.x = floor(x);
origin.y = floor(y);
}
CGSize size = rect.size;
CGFloat width = size.width;
CGFloat height = size.height;
CGFloat ceilWidth = ceil(width);
CGFloat ceilHeight = ceil(height);
if (fabs(ceilWidth - width) < pow(10, kK) * RSK_EPSILON * fabs(ceilWidth + width) || fabs(ceilWidth - width) < RSK_MIN ||
fabs(ceilHeight - height) < pow(10, kK) * RSK_EPSILON * fabs(ceilHeight + height) || fabs(ceilHeight - height) < RSK_MIN) {
size.width = ceilWidth;
size.height = ceilHeight;
} else {
size.width = floor(width);
size.height = floor(height);
}
return CGRectMake(origin.x, origin.y, size.width, size.height);
}
CGRect RSKRectScaleAroundPoint(CGRect rect, CGPoint point, CGFloat sx, CGFloat sy)
{
CGAffineTransform translationTransform, scaleTransform;
translationTransform = CGAffineTransformMakeTranslation(-point.x, -point.y);
rect = CGRectApplyAffineTransform(rect, translationTransform);
scaleTransform = CGAffineTransformMakeScale(sx, sy);
rect = CGRectApplyAffineTransform(rect, scaleTransform);
translationTransform = CGAffineTransformMakeTranslation(point.x, point.y);
rect = CGRectApplyAffineTransform(rect, translationTransform);
return rect;
}
bool RSKPointIsNull(CGPoint point)
{
return CGPointEqualToPoint(point, RSKPointNull);
}
CGPoint RSKPointRotateAroundPoint(CGPoint point, CGPoint pivot, CGFloat angle)
{
CGAffineTransform translationTransform, rotationTransform;
translationTransform = CGAffineTransformMakeTranslation(-pivot.x, -pivot.y);
point = CGPointApplyAffineTransform(point, translationTransform);
rotationTransform = CGAffineTransformMakeRotation(angle);
point = CGPointApplyAffineTransform(point, rotationTransform);
translationTransform = CGAffineTransformMakeTranslation(pivot.x, pivot.y);
point = CGPointApplyAffineTransform(point, translationTransform);
return point;
}
CGFloat RSKPointDistance(CGPoint p1, CGPoint p2)
{
CGFloat dx = p1.x - p2.x;
CGFloat dy = p1.y - p2.y;
return sqrt(pow(dx, 2) + pow(dy, 2));
}
RSKLineSegment RSKLineSegmentMake(CGPoint start, CGPoint end)
{
return (RSKLineSegment){ start, end };
}
RSKLineSegment RSKLineSegmentRotateAroundPoint(RSKLineSegment line, CGPoint pivot, CGFloat angle)
{
return RSKLineSegmentMake(RSKPointRotateAroundPoint(line.start, pivot, angle),
RSKPointRotateAroundPoint(line.end, pivot, angle));
}
/*
Equations of line segments:
pA = ls1.start + uA * (ls1.end - ls1.start)
pB = ls2.start + uB * (ls2.end - ls2.start)
In the case when `pA` is equal `pB` we have:
x1 + uA * (x2 - x1) = x3 + uB * (x4 - x3)
y1 + uA * (y2 - y1) = y3 + uB * (y4 - y3)
uA = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3) / (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
uB = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3) / (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
numeratorA = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)
denominatorA = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
numeratorA = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)
denominatorB = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
[1] Denominators are equal.
[2] If numerators and denominator are zero, then the line segments are coincident. The point of intersection is the midpoint of the line segment.
x = (x1 + x2) * 0.5
y = (y1 + y2) * 0.5
or
x = (x3 + x4) * 0.5
y = (y3 + y4) * 0.5
[3] If denominator is zero, then the line segments are parallel. There is no point of intersection.
[4] If `uA` and `uB` is included into the interval [0, 1], then the line segments intersects in the point (x, y).
x = x1 + uA * (x2 - x1)
y = y1 + uA * (y2 - y1)
or
x = x3 + uB * (x4 - x3)
y = y3 + uB * (y4 - y3)
*/
CGPoint RSKLineSegmentIntersection(RSKLineSegment ls1, RSKLineSegment ls2)
{
CGFloat x1 = ls1.start.x;
CGFloat y1 = ls1.start.y;
CGFloat x2 = ls1.end.x;
CGFloat y2 = ls1.end.y;
CGFloat x3 = ls2.start.x;
CGFloat y3 = ls2.start.y;
CGFloat x4 = ls2.end.x;
CGFloat y4 = ls2.end.y;
CGFloat numeratorA = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
CGFloat numeratorB = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
CGFloat denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
// Check the coincidence.
if (fabs(numeratorA) < RSK_EPSILON && fabs(numeratorB) < RSK_EPSILON && fabs(denominator) < RSK_EPSILON) {
return CGPointMake((x1 + x2) * 0.5, (y1 + y2) * 0.5);
}
// Check the parallelism.
if (fabs(denominator) < RSK_EPSILON) {
return RSKPointNull;
}
// Check the intersection.
CGFloat uA = numeratorA / denominator;
CGFloat uB = numeratorB / denominator;
if (uA < 0 || uA > 1 || uB < 0 || uB > 1) {
return RSKPointNull;
}
return CGPointMake(x1 + uA * (x2 - x1), y1 + uA * (y2 - y1));
}