iPhone 부드러운 스케치 그리기 알고리즘
iPhone에서 스케치 앱을 작업 중입니다. 나는 그것을 작동했지만 여기에서 본 것처럼 예쁘지 않습니다.
그리고 그림을 부드럽게하기위한 제안을 찾고 있습니다. 기본적으로 사용자가 전화 한 화면에 손가락을 놓을 때
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
그런 다음 배열에서 단일 터치를 수집합니다.
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
사용자가 화면에서 손가락을 뗐을 때
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
그런 다음 사용하여 배열의 모든 점을 그립니다.
NSMutableArray *points = [collectedArray points];
CGPoint firstPoint;
[[points objectAtIndex:0] getValue:&firstPoint];
CGContextMoveToPoint(context, firstPoint.x, firstPoint.y);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineJoin(context, kCGLineJoinRound);
for (int i=1; i < [points count]; i++) {
NSValue *value = [points objectAtIndex:i];
CGPoint point;
[value getValue:&point];
CGContextAddLineToPoint(context, point.x, point.y);
}
CGContextStrokePath(context);
UIGraphicsPushContext(context);
그리고 이제는 "스케치북"앱처럼 그림을 개선하고 싶습니다.
배열의 모든 포인트를 재정렬하는 신호 처리 알고리즘과 관련이 있다고 생각하지만 확실하지 않습니다. 어떤 도움이라도 대단히 감사하겠습니다.
사전에 Thankz :)
이와 같이 곡선을 매끄럽게하는 가장 쉬운 방법은 직선 세그먼트 대신 베 지어 곡선을 사용하는 것입니다. 이에 대한 수학은 여러 점을 통과하는 곡선을 매끄럽게 만드는 데 필요한 곡선을 계산하는 방법을 설명하는 이 문서 ( 이 답변 에서 가리키는)를 참조하십시오 .
Core Plot 프레임 워크는 이제 플롯 의 곡선을 매끄럽게 할 수있는 기능이 있다고 믿습니다 . 따라서 이러한 유형의 매끄럽게 구현하는 데 사용되는 코드를 볼 수 있습니다.
이러한 스무딩 루틴은 빠르고 비교적 쉽게 구현할 수 있기 때문에 마법 같은 것은 없습니다.
CGPoint midPoint(CGPoint p1, CGPoint p2)
{
return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
previousPoint1 = [touch previousLocationInView:self];
previousPoint2 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
previousPoint2 = previousPoint1;
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
// calculate mid point
CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
UIGraphicsBeginImageContext(self.imageView.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.imageView.image drawInRect:CGRectMake(0, 0, self.imageView.frame.size.width, self.imageView.frame.size.height)];
CGContextMoveToPoint(context, mid1.x, mid1.y);
// Use QuadCurve is the key
CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 2.0);
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextStrokePath(context);
self.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
나는 주제를 정말 좋아합니다. 모든 구현, 특히 Krzysztof Zabłocki와 Yu-Sen Han에 감사드립니다. 패닝 속도 (사실 마지막 터치 사이의 거리)에 따라 선 두께를 변경하기 위해 한유 선 버전을 수정했습니다. 또한 점 그리기를 구현했습니다 (touchBegan 및 touchEnded 위치가 서로 가까이있는 경우) 결과는 다음과 같습니다.
선 두께를 정의하기 위해 거리 함수를 선택했습니다.
(이유는 묻지 마세요 ... 잘 어울리지 만 더 나은 것을 찾을 수있을 것입니다)
CGFloat dist = distance(previousPoint1, currentPoint);
CGFloat newWidth = 4*(atan(-dist/15+1) + M_PI/2)+2;
힌트 하나 더. 두께가 매끄럽게 변경되는지 확인하기 위해 이전 세그먼트의 두께와 사용자 지정 계수에 따라 경계를 지정했습니다.
self.lineWidth = MAX(MIN(newWidth,lastWidth*WIDTH_RANGE_COEF),lastWidth/WIDTH_RANGE_COEF);
kyoji의 대답 을 재사용 가능한 하위 클래스 인 Swift로 번역 했습니다UIImageView
. 하위 클래스를 TouchDrawImageView
사용하면 사용자가 손가락으로 이미지보기에 그릴 수 있습니다.
이 TouchDrawImageView
클래스를 프로젝트에 추가했으면 스토리 보드를 열고
TouchDrawImageView
이미지보기의 "사용자 지정 클래스"로 선택- 이미지보기의 "사용자 상호 작용 활성화"속성을 확인하십시오.
다음은 코드입니다 TouchDrawImageView.swift
.
import UIKit
class TouchDrawImageView: UIImageView {
var previousPoint1 = CGPoint()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
previousPoint1 = touch.previousLocation(in: self)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let previousPoint2 = previousPoint1
previousPoint1 = touch.previousLocation(in: self)
let currentPoint = touch.location(in: self)
// calculate mid point
let mid1 = midPoint(p1: previousPoint1, p2: previousPoint2)
let mid2 = midPoint(p1: currentPoint, p2: previousPoint1)
UIGraphicsBeginImageContext(self.frame.size)
guard let context = UIGraphicsGetCurrentContext() else { return }
if let image = self.image {
image.draw(in: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
}
context.move(to: mid1)
context.addQuadCurve(to: mid2, control: previousPoint1)
context.setLineCap(.round)
context.setLineWidth(2.0)
context.setStrokeColor(red: 1.0, green: 0, blue: 0, alpha: 1.0)
context.strokePath()
self.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
func midPoint(p1: CGPoint, p2: CGPoint) -> CGPoint {
return CGPoint(x: (p1.x + p2.x) / 2.0, y: (p1.y + p2.y) / 2.0)
}
}
입력 해 주셔서 감사합니다. 공간이 필요하기 때문에 여기에서 퀘스트를 업데이트합니다.
거의 성공하지 못한 제안한 corePlot 및 Bezier 곡선 솔루션을 모두 찾습니다.
corePlot의 경우 int 배열에서 그래프 플롯을 가져올 수 있지만 커브 스무딩과 관련된 것을 찾을 수 없습니다 .BTW 여기에서는 임의의 숫자로 CPScatterPlot을 사용하고 있습니다.
Bezier 곡선에 관해서는 나의 탐구가 여기 로 이끈다 iOS에서 Spline 구현과 관련이있다
CatmullRomSpline *myC = [[CatmullRomSpline alloc] initAtPoint:CGPointMake(1.0, 1.0)];
[myC addPoint:CGPointMake(1.0, 1.5)];
[myC addPoint:CGPointMake(1.0, 1.15)];
[myC addPoint:CGPointMake(1.0, 1.25)];
[myC addPoint:CGPointMake(1.0, 1.23)];
[myC addPoint:CGPointMake(1.0, 1.24)];
[myC addPoint:CGPointMake(1.0, 1.26)];
NSLog(@"xxppxx %@",[myC asPointArray]);
NSLog(@"xxppxx2 %@",myC.curves);
그리고 내가 얻는 결과는 다음과 같습니다.
2011-02-24 14:45:53.915 DVA[10041:40b] xxppxx (
"NSPoint: {1, 1}",
"NSPoint: {1, 1.26}"
)
2011-02-24 14:45:53.942 DVA[10041:40b] xxppxx2 (
"QuadraticBezierCurve: 0x59eea70"
)
나는 거기에서 어떻게 가는지 잘 모르겠습니다. 그래서 나는 그 정면에도 붙어 있습니다 :(
마지막 리소스로 GLPaint를 찾아 보았습니다. OpenGLES를 사용하고 "소프트 도트"스프라이트를 사용하여 배열의 점을 플로팅합니다. 나는 그것이 문제를 고치기보다는 피하는 것과 같다는 것을 안다. 하지만 어쨌든 여기서 발견 한 내용을 공유 할 것 같습니다.
Black은 GLPaint이고 흰색은 오래된 방법입니다. 그리고 마지막은 "Sketch Book"앱의 그림입니다.
나는 여전히 이것을 제대로하기 위해 노력하고 있으며, 어떤 추가 제안이라도 가장 환영받습니다.
GLPaint 코드에서 어리석은 점을 제거합니다.
변화
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
이 기능
//Ändrat av OLLE
/*
// Convert touch point from UIView referential to OpenGL one (upside-down flip)
if (firstTouch) {
firstTouch = NO;
previousLocation = [touch previousLocationInView:self];
previousLocation.y = bounds.size.height - previousLocation.y;
} else {
location = [touch locationInView:self];
location.y = bounds.size.height - location.y;
previousLocation = [touch previousLocationInView:self];
previousLocation.y = bounds.size.height - previousLocation.y;
}
*/
location = [touch locationInView:self];
location.y = bounds.size.height - location.y;
previousLocation = [touch previousLocationInView:self];
previousLocation.y = bounds.size.height - previousLocation.y;
//Ändrat av OLLE//
나는 이것이 우리 문제의 해결책이 아니라는 것을 알고 있지만 그것은 무언가입니다.
참고 URL : https://stackoverflow.com/questions/5076622/iphone-smooth-sketch-drawing-algorithm
'IT Share you' 카테고리의 다른 글
jslint 오류 '루프 내에서 함수를 만들지 마십시오'를 수정하는 방법? (0) | 2020.12.04 |
---|---|
Excel에서 특정 워크 시트를 활성화하는 방법은 무엇입니까? (0) | 2020.12.04 |
함수 반환 유형 및 인수 유형을 아는 방법? (0) | 2020.12.04 |
FormsAuthentication 쿠키 이름을 변경할 수 있습니까? (0) | 2020.12.04 |
커밋 후 SVN 패치 생성 (0) | 2020.12.04 |