2012-10-24 21 views
5
public static ArrayList<IntPoint> getCircleLineIntersectionPoint(IntPoint pointA, IntPoint pointB, IntPoint center, int radius) { 
    // returns a list of intersection points between a line which passes through given points, 
    // pointA and pointB, and a circle described by given radius and center coordinate 

    double disc, A, B, C, slope, c; 
    double x1, x2, y1, y2; 
    IntPoint point1, point2; 
    ArrayList<IntPoint> intersections = new ArrayList<IntPoint>(); 
    try{ 
     slope = Util.calculateSlope(pointA, pointB); 
    }catch (UndefinedSlopeException e){   
     C = Math.pow(center.y, 2) + Math.pow(pointB.x, 2) - 2 * pointB.x * center.x + Math.pow(center.x, 2) - Math.pow(radius, 2); 
     B = -2 * center.y; 
     A = 1; 
     disc = Math.pow(B, 2) - 4 * 1 * C; 
     if (disc < 0){ 
      return intersections; 
     } 
     else{ 
      y1 = (-B + Math.sqrt(disc))/(2 * A); 
      y2 = (-B - Math.sqrt(disc))/(2 * A); 

      x1 = pointB.x; 
      x2 = pointB.x; 
     } 
     point1 = new IntPoint((int)x1, (int)y1); 
     point2 = new IntPoint((int)x2, (int)y2); 
     if (Util.euclideanDistance(pointA, point2) > Util.euclideanDistance(pointA, point1)){ 
      intersections.add(point1); 
     } 
     else{ 
      intersections.add(point2); 
     } 
     return intersections; 
    } 
    if (slope == 0){ 
     C = Math.pow(center.x, 2) + Math.pow(center.y, 2) + Math.pow(pointB.y, 2) - 2 * pointB.y * center.y - Math.pow(radius, 2); 
     B = -2 * center.x; 
     A = 1; 
     disc = Math.pow(B, 2) - 4 * 1 * C; 
     if (disc < 0){ 
      return intersections; 
     } 
     else{ 
      x1 = (-B + Math.sqrt(disc))/(2*A); 
      x2 = (-B - Math.sqrt(disc))/(2*A); 
      y1 = pointB.y; 
      y2 = pointB.y; 
     } 
    } 
    else{ 
     c = slope * pointA.x + pointA.y; 
     B = (2 * center.x + 2 * center.y * slope + 2 * c * slope); 
     A = 1 + Math.pow(slope, 2); 
     C = (Math.pow(center.x, 2) + Math.pow(c, 2) + 2 * center.y * c + Math.pow(center.y, 2) - Math.pow(radius, 2)); 
     disc = Math.pow(B, 2) - (4 * A * C); 

     if (disc < 0){ 
      return intersections; 
     } 
     else{ 
      x1 = (-B + Math.sqrt(disc))/(2 * A); 
      x2 = (-B - Math.sqrt(disc))/(2 * A); 

      y1 = slope * x1 - c; 
      y2 = slope * x2 - c; 
     } 
    } 

    point1 = new IntPoint((int)x1, (int)y1); 
    point2 = new IntPoint((int)x2, (int)y2); 
    if (Util.euclideanDistance(pointA, point2) > Util.euclideanDistance(pointA, point1)){ 
     //if (Util.angleBetween(pointA, pointB, point1) < Math.PI/2){ 
      intersections.add(point1); 
     //} 
    } 
    else{ 
     //if (Util.angleBetween(pointA, pointB, point1) < Math.PI/2){ 
      intersections.add(point2); 
     //} 
    }  
    return intersections; 
} 

मैं उपरोक्त एल्गोरिदम का उपयोग एक सर्कल और रेखा के बीच चौराहे के परीक्षण के लिए कर रहा हूं। यह कभी-कभी ठीक काम करता है लेकिन दूसरी बार यह विफल रहता है। कोड समीकरण का प्रतिनिधित्व करता है जो एक्स के साथ सर्कल और लाइन समीकरण (x-a)^+(y-b)^2=r^2 और y = mx - mx1 + y1 से एक साथ हल करने से लिया गया है। क्या किसी को यह पता चला है कि मैं अपने गणित या अन्य जगहों में गलत कहां जा रहा हूं?सर्किल लाइन छेड़छाड़ अंक

+1

के साथ एक समाधान है कि आप कुछ लाइनों और हलकों कि कारण यह विफल करने का एक उदाहरण दे सकते हैं? और आप अपने एक्स, वाई निर्देशांक को पूर्णांक में क्यों परिवर्तित करते हैं? –

+0

क्या आप अपने वेरिएबल घोषित करने का प्रयास कर सकते हैं जहां आप उनका उपयोग करते हैं, और कहीं और पूरी तरह से नहीं? और उन्हें और अधिक सार्थक नाम दें? ('ढलान 'एक अच्छी शुरुआत है, हालांकि।) इसके अलावा, मैं उन बिंदुओं की अपेक्षा भी नहीं करूंगा जो आप पूर्णांक निर्देशांक रखने के लिए देख रहे हैं, इसलिए कास्टिंग बहुत संदिग्ध प्रतीत होता है। –

+0

इंटपॉइंट क्लास का इस्तेमाल लाइब्रेरी द्वारा किया जाता है और निर्देशांक int – cobie

उत्तर

22

आपकी गणना काफी लंबी लगती है, और मुझे आपके द्वारा परीक्षण किए जाने वाले विभिन्न मामलों का उपयोग नहीं दिखाई देता है। वैसे भी, क्योंकि मुझे रोचक समस्या मिली है, मैंने इसे स्वयं हल करने का प्रयास किया और निम्नलिखित के साथ आया। double radius को int radius द्वारा प्रतिस्थापित करने के लिए स्वतंत्र महसूस करें और IntPoint एस का उपयोग करें, लेकिन सावधान रहें कि टिप्पणियों में चर्चा के अनुसार हर बार जब आप कास्ट करते हैं, तो परिणाम सटीक पूर्णांक अंतरंग बिंदु गलत नहीं होंगे।

प्रदर्शन की गणना की पृष्ठभूमि यह है: बिंदु ए से, वेक्टर एबी का एक स्केल संस्करण सर्कल पर एक बिंदु पर इंगित करता है। उस बिंदु से केंद्र से दूरी त्रिज्या है। इसलिए, एसी + स्केलिंग फैक्टर * एबी | = आर।

import java.util.Arrays; 
import java.util.Collections; 
import java.util.List; 

public class CircleLine { 

    public static List<Point> getCircleLineIntersectionPoint(Point pointA, 
      Point pointB, Point center, double radius) { 
     double baX = pointB.x - pointA.x; 
     double baY = pointB.y - pointA.y; 
     double caX = center.x - pointA.x; 
     double caY = center.y - pointA.y; 

     double a = baX * baX + baY * baY; 
     double bBy2 = baX * caX + baY * caY; 
     double c = caX * caX + caY * caY - radius * radius; 

     double pBy2 = bBy2/a; 
     double q = c/a; 

     double disc = pBy2 * pBy2 - q; 
     if (disc < 0) { 
      return Collections.emptyList(); 
     } 
     // if disc == 0 ... dealt with later 
     double tmpSqrt = Math.sqrt(disc); 
     double abScalingFactor1 = -pBy2 + tmpSqrt; 
     double abScalingFactor2 = -pBy2 - tmpSqrt; 

     Point p1 = new Point(pointA.x - baX * abScalingFactor1, pointA.y 
       - baY * abScalingFactor1); 
     if (disc == 0) { // abScalingFactor1 == abScalingFactor2 
      return Collections.singletonList(p1); 
     } 
     Point p2 = new Point(pointA.x - baX * abScalingFactor2, pointA.y 
       - baY * abScalingFactor2); 
     return Arrays.asList(p1, p2); 
    } 

    static class Point { 
     double x, y; 

     public Point(double x, double y) { this.x = x; this.y = y; } 

     @Override 
     public String toString() { 
      return "Point [x=" + x + ", y=" + y + "]"; 
     } 
    } 


    public static void main(String[] args) { 
     System.out.println(getCircleLineIntersectionPoint(new Point(-3, -3), 
       new Point(-3, 3), new Point(0, 0), 5)); 
     System.out.println(getCircleLineIntersectionPoint(new Point(0, -2), 
       new Point(1, -2), new Point(1, 1), 5)); 
     System.out.println(getCircleLineIntersectionPoint(new Point(1, -1), 
       new Point(-1, 0), new Point(-1, 1), 5)); 
     System.out.println(getCircleLineIntersectionPoint(new Point(-3, -3), 
       new Point(-2, -2), new Point(0, 0), Math.sqrt(2))); 
    } 
+0

अब तक एक आकर्षण की तरह काम करता है ... धन्यवाद मुझे कहना होगा !! – cobie

+0

क्या आप – cobie

+1

कोड के इस टुकड़े में क्या हो रहा है, इस बारे में थोड़ा और स्पष्टीकरण दे सकते हैं, 'ए', बी और 'सी' हल करने के लिए एक्वाड्रैटिक समीकरण के गुणांक हैं, हालांकि मैं संस्करण (1,) पी और' q'। चूंकि वास्तविक बी में एक कारक के रूप में 2 शामिल हैं, और इसलिए पी होगा, लेकिन पी को 2 से विभाजित किया जाना चाहिए, मैं वास्तव में मध्यवर्ती चर के लिए केवल बी और पी का आधा उपयोग करता हूं। ए, बी और सी कैसे प्राप्त करें ... अच्छी तरह से, वेक्टर एसी (ए से सर्कल सेंटर तक) क्या है, समन्वयपूर्वक? एबी क्या है? ऊपर दिए गए समीकरण को स्क्वायर करें, बदलें ... ;-) –

0

यहाँ import javax.vecmath.Vector2d;

static Vector2d[] circleLineIntersection1(Vector2d a, Vector2d b, Vector2d o, double radius) { 

    Vector2d p1 = new Vector2d(a); 
    Vector2d p2 = new Vector2d(b); 
    p1.sub(o); 
    p2.sub(o); 

    Vector2d d = new Vector2d(); 
    d.sub(p2, p1); 

    double det = p1.x * p2.y - p2.x * p1.y; 

    double dSq = d.lengthSquared(); 

    double discrimant = radius * radius * dSq - det * det; 

    if (discrimant < 0) { 
     return new Vector2d[0]; 
    } 

    if (discrimant == 0) { 
     Vector2d[] t = new Vector2d[1]; 
     t[0] = new Vector2d(det * d.y/dSq + o.x, -det * d.x/dSq + o.y); 

     return t; 
    } 

    double discSqrt = Math.sqrt(discrimant); 

    double sgn = 1; 
    if (d.y < 0) { 
     sgn = -1; 
    } 

    Vector2d[] t = new Vector2d[2]; 
    t[0] = new Vector2d((det * d.y + sgn * d.x * discSqrt)/dSq + o.x, (-det * d.x + Math.abs(d.y) * discSqrt)/dSq + o.y); 
    t[1] = new Vector2d((det * d.y - sgn * d.x * discSqrt)/dSq + o.x, (-det * d.x - Math.abs(d.y) * discSqrt)/dSq + o.y); 
    return t; 

} 
संबंधित मुद्दे