質問

I need to find the largest arc created from the intersection of a circle and a rectangle. I have the center of the circle, the radius and the coordinates of the rectangle, and I need to find the angle of the intersection points with the center of the circle.

Problem Diagram

I have a code that works, but it computes the solution iterating the points of the circumference, and I was wondering if there's a more elegant way to calculate the solution using trigonometry instead of "brute force".

That's my code:

import 'dart:math';

class CircleTheSquare {
  final Point     _circleCenter;
  final int       _circleRadius;
  final Rectangle _box;


  CircleTheSquare(this._circleCenter, this._circleRadius, this._box);


  Map<String, double> get arc {
    Map res = new Map();

    double angle = .0;
    double angleIn;
    double angleOut;
    double increment = 1.0;

    while (true) {
      if (angle > 360.0 && angleIn == null) {
        break;
      }

      // Finds a point of intersection (next points will be inside 
      // of the rectangle).
      if (!_isOutside(angle) && _isOutside(angle - increment)) {
        angleIn = angle;
      }

      // Finds next intersection (next points will be outside 
      // of the rectangle).
      if (angleIn != null &&
          _isOutside(angle + increment) && !_isOutside(angle)) {

        angleOut = angle;

        // Adds the arc to result only there's not a previous largest arc.
        if (res["in"] == null ||
            angleOut - angleIn > res["arc"]) {

          res["in"]  = angleIn;
          res["arc"] = angleOut - angleIn;
        }
        angleIn = null;
        angleOut = null;
      }
      angle += increment;
    }

    // If there's no intersections. 
    // -- For simplicity, we will assume that the
    //    rectangle and the circle intersect or that the circle is 
    //    inside of the rectangle).
    if (res["in"] == null) {
      res = {"in" : 0.0, "arc" : 360.0};
    }

    return res;
  }


  bool _isOutside(double a) {
    var res;

    double cx = _circleCenter.x + (_circleRadius * cos(a * (PI / 180)));
    double cy = _circleCenter.y + (_circleRadius * sin(a * (PI / 180)));

    bool hOut = cx < _box.left || cx > _box.left + _box.width;
    bool vOut = cy < _box.top || cy > _box.top + _box.height;

    if (hOut || vOut) {
      res = true;
    } else {
      res = false;
    }

    return res;
  }
}


main() {
  CircleTheSquare a = new CircleTheSquare(new Point(250, 250), 100,
                                          new Rectangle(0,0,500,500));

  print(a.arc); // {in: 0.0, arc: 360.0}

  CircleTheSquare b = new CircleTheSquare(new Point(450, 250), 100,
                                          new Rectangle(0,0,500,500));

  print(b.arc); // {in: 60.0, arc: 240.0}

  CircleTheSquare c = new CircleTheSquare(new Point(420, 420), 100,
                                          new Rectangle(0,0,500,500));

  print(c.arc); // 4 intersections, returns the largest arc:
                          // {in: 127.0, arc: 196.0}
}
役に立ちましたか?

解決

  1. Shift all coordinates to make circle zero-centered (box.left = box.left - circlecenter.x etc) for simplicity
  2. Find intersections of circle with sides of rectangle. For example, for left side solve (box.left)^2 + y^2 = radius^2, check that point lies on side, add intersection point to list
  3. Sort intersection points by angle (probably, it is automatically provided by side check order), find the largest angle interval for arcs inside the rectangle

他のヒント

As you expect, there are better and more direct methods to solve this. You may want to look at e.g. http://mathworld.wolfram.com/Circle-LineIntersection.html. Split the rectangle into lines, get intersection points for each line, determine if they are within the actual line segments, then find the points that give the largest arc.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top