Finding points on a rectangle at a given angle

后端 未结 7 2006
没有蜡笔的小新
没有蜡笔的小新 2020-12-14 02:43

I\'m trying to draw a gradient in a rectangle object, with a given angle (Theta), where the ends of the gradient are touching the perimeter of the rectangle.

7条回答
  •  眼角桃花
    2020-12-14 03:16

    Ok, whew!, I finally got this one.

    NOTE: I based this off of belisarius's awesome answer. If you like this, please like his, too. All I did was turn what he said into code.

    Here's what it looks like in Objective-C. It should be simple enough to convert to whatever your favorite language is.

    + (CGPoint) edgeOfView: (UIView*) view atAngle: (float) theta
    {
        // Move theta to range -M_PI .. M_PI
        const double twoPI = M_PI * 2.;
        while (theta < -M_PI)
        {
            theta += twoPI;
        }
    
        while (theta > M_PI)
        {
            theta -= twoPI;
        }
    
        // find edge ofview
        // Ref: http://stackoverflow.com/questions/4061576/finding-points-on-a-rectangle-at-a-given-angle
        float aa = view.bounds.size.width;                                          // "a" in the diagram
        float bb = view.bounds.size.height;                                         // "b"
    
        // Find our region (diagram)
        float rectAtan = atan2f(bb, aa);
        float tanTheta = tan(theta);
    
        int region;
        if ((theta > -rectAtan)
        &&  (theta <= rectAtan) )
        {
            region = 1;
        }
        else if ((theta >  rectAtan)
        &&       (theta <= (M_PI - rectAtan)) )
        {
            region = 2;
        }
        else if ((theta >   (M_PI - rectAtan))
        ||       (theta <= -(M_PI - rectAtan)) )
        {
            region = 3;
        }
        else
        {
            region = 4;
        }
    
        CGPoint edgePoint = view.center;
        float xFactor = 1;
        float yFactor = 1;
    
        switch (region)
        {
            case 1: yFactor = -1;       break;
            case 2: yFactor = -1;       break;
            case 3: xFactor = -1;       break;
            case 4: xFactor = -1;       break;
        }
    
        if ((region == 1)
        ||  (region == 3) )
        {
            edgePoint.x += xFactor * (aa / 2.);                                     // "Z0"
            edgePoint.y += yFactor * (aa / 2.) * tanTheta;
        }
        else                                                                        // region 2 or 4
        {
            edgePoint.x += xFactor * (bb / (2. * tanTheta));                        // "Z1"
            edgePoint.y += yFactor * (bb /  2.);
        }
    
        return edgePoint;
    }
    

    In addition, here's a little test-view I created to verify that it works. Create this view and put it somewhere, it will make another little view scoot around the edge.

    @interface DebugEdgeView()
    {
        int degrees;
        UIView *dotView;
        NSTimer *timer;
    }
    
    @end
    
    @implementation DebugEdgeView
    
    - (void) dealloc
    {
        [timer invalidate];
    }
    
    
    - (id) initWithFrame: (CGRect) frame
    {
        self = [super initWithFrame: frame];
        if (self)
        {
            self.backgroundColor = [[UIColor magentaColor] colorWithAlphaComponent: 0.25];
            degrees = 0;
            self.clipsToBounds = NO;
    
            // create subview dot
            CGRect dotRect = CGRectMake(frame.size.width / 2., frame.size.height / 2., 20, 20);
            dotView = [[DotView alloc] initWithFrame: dotRect];
            dotView.backgroundColor = [UIColor magentaColor];
            [self addSubview: dotView];
    
            // move it around our edges
            timer = [NSTimer scheduledTimerWithTimeInterval: (5. / 360.)
                                                     target: self
                                                   selector: @selector(timerFired:)
                                                   userInfo: nil
                                                    repeats: YES];
        }
    
        return self;
    }
    
    
    - (void) timerFired: (NSTimer*) timer
    {
        float radians = ++degrees * M_PI / 180.;
        if (degrees > 360)
        {
            degrees -= 360;
        }
    
        dispatch_async(dispatch_get_main_queue(), ^{
            CGPoint edgePoint = [MFUtils edgeOfView: self atAngle: radians];
            edgePoint.x += (self.bounds.size.width  / 2.) - self.center.x;
            edgePoint.y += (self.bounds.size.height / 2.) - self.center.y;
            dotView.center = edgePoint;
        });
    }
    
    @end
    

提交回复
热议问题