如何检查用户是否在CGPath附近轻敲?

时间:2009-07-17 14:41:43

标签: iphone quartz-graphics

情景:

我有一套CGPath s。它们大多只是线条(即不是封闭的形状)。它们以UIView的绘制方法在屏幕上绘制。

如何检查用户是否在其中一条路径附近轻敲?

这就是我的工作:

UIGraphincsBeginImageContext(CGPathGetBoundingBox(path));
CGContextRef g = UIGraphicsGetCurrentContext();
CGContextAddPath(g,path);
CGContextSetLineWidth(g,15);
CGContextReplacePathWithStrokedPath(g);
CGPath clickArea = CGContextCopyPath(g);  //Not documented
UIGraphicsEndImageContext();

所以我正在做的是创建一个图像上下文,因为它具有我需要的功能。然后我将路径添加到上下文中,并将行宽设置为15.此时描绘路径将创建我可以在其中检查以查找点击的点击区域。所以我通过告诉上下文将路径转换为描边路径,然后将该路径复制回另一个CGPath来获得该描述路径。之后,我可以查看:

if (CGPathContainsPoint(clickArea,NULL,point,NO)) { ...

这一切都运作良好,但CGContextCopyPath,没有记录,似乎是一个坏主意,使用明显的原因。关于为此目的制作CGContext也存在一定的弊端。

那么,有没有人有任何想法?如何检查用户是否在CGPath的任何区域附近(在这种情况下,在15个像素内)点击?

3 个答案:

答案 0 :(得分:20)

在iOS 5.0及更高版本中,可以使用CGPathCreateCopyByStrokingPath更简单地完成此操作:

CGPathRef strokedPath = CGPathCreateCopyByStrokingPath(path, NULL, 15,
    kCGLineCapRound, kCGLineJoinRound, 1);
BOOL pointIsNearPath = CGPathContainsPoint(strokedPath, NULL, point, NO);
CGPathRelease(strokedPath);

if (pointIsNearPath) ...

答案 1 :(得分:2)

好吧,我找到了答案。它使用CGPathApply:

clickArea = CGPathCreateMutable();
CGPathApply(path,clickArea,&createClickArea);

void createClickArea (void *info, const CGPathElement *elem) {
  CGPathElementType type = elem->type;
  CGMutablePathRef path = (CGMutablePathRef)info;
  static CGPoint last;
  static CGPoint subpathStart;
  switch (type) {
    case kCGPathElementAddCurveToPoint:
    case kCGPathElementAddQuadCurveToPoint:
      break;
    case kCGPathElmentCloseSubpath:
    case kCGPathElementMoveToPoint: {
      CGPoint p = type == kCGPathElementAddLineToPoint ? elem->points[0] : subpathStart;
      if (CGPointEqualToPoint(p,last)) {
        return;
      }
      CGFloat rad = atan2(p.y - last.y, p.x - last.x);
      CGFloat xOff = CLICK_DIST * cos(rad);
      CGFloat yOff = CLICK_DIST * sin(rad);
      CGPoint a = CGPointMake(last.x - xOff, last.y - yOff);
      CGPoint b = CGPointMake(p.x + xOff, p.y + yOff);
      rad += M_PI_2;
      xOff = CLICK_DIST * cos(rad);
      yOff = CLICK_DIST * sin(rad);
      CGPathMoveToPoint(path, NULL, a.x - xOff, a.y - yOff);
      CGPathAddLineToPoint(path, NULL, a.x + xOff, a.y + yOff);
      CGPathAddLineToPoint(path, NULL, b.x + xOff, b.y + yOff);
      CGPathAddLineToPoint(path, NULL, b.x - xOff, b.y - yOff);
      CGPathCloseSubpath(path);
      last = p;
      break; }
    case kCGPathElementMoveToPoint:
      subpathStart = last = elem->points[0];
      break;
  }
}

基本上它只是我自己的ReplacePathWithStrokedPath方法,但它现在只适用于行。

答案 2 :(得分:0)

在Swift

create table relation(num1 int,num2 int, num3 int);

insert into relation values(1,2,3);
insert into relation values(2,4,5);
insert into relation values(3,4,null);

create table info(num int, a_lot_of_other_info varchar2(100));
insert into info
   select 1,'asdff' from dual union all
   select 2,'werwr' from dual union all
   select 3,'erert' from dual union all
   select 4,'ghfgh' from dual union all
   select 5,'cvbcb' from dual 

 select a.num
        ,max(a_lot_of_other_info) as a_lot_of_other_info
        ,count(*) as num_of_times
   from info a
   join (select val
           from relation a
         unpivot(val for x in (num1,num2,num3))
         )b
      on a.num=b.val  
 group by a.num 
 order by 1