2010-09-19 6 views
5

Попытка сделать очень простую булевую функцию, которая найдет, пересечет ли линия сферу.Найти, если линия пересекает сферу

Это не похоже на то, что я хочу, хотя вопрос был похож: Intersection of a line and a Sphere?

Кроме того, я попытался алгоритмы, перечисленные в:

http://www.docstoc.com/docs/7747820/Intersection-of-a-Line-and-a-Sphere

и

http://www.ccs.neu.edu/home/fell/CSU540/programs/RayTracingFormulas.htm

без реальных удачи.

Мой последний код (в Haskell) выглядит следующим образом:

data Point = Point { x :: Float, y :: Float, z :: Float} deriving (Eq, Show, Read) 
data Sphere = Sphere { center :: Point, radius :: Float } deriving (Eq, Show, Read) 

inView :: Point -> Point -> Sphere -> Bool 
inView (Point x1 y1 z1) (Point x2 y2 z2) (Sphere (Point x3 y3 z3) r) 
    | result > 0 && result < r = False 
    | otherwise    = True 
    where result = top/bot 
     top = (x3 - x1) * (x2 - x1) + (y3 - y1) * (y2 - y1) + (z3 - z1) * (z2 - z1) 
     bot = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1) 

Где она возвращает истину, если 2 точки имеет прямую линию визирования. Это работает для некоторых простых случаев, но не для других, которые должны работать, например:

inView (Point {x = 43.64, y = -183.20, z = 187.37}) (Point {x = 42.04, y = -183.58, z = 187.37}) (Sphere (Point 0 0 0) 5) 

Любая помощь будет оценена.

+1

Алгоритм, который вы использовали, должен быть неправильным. Легко видеть, что при анализе размеров - 'top' и' bot' имеют размеры области, а 'result' - безразмерные; 'r' имеет размерность Length, поэтому' result kennytm

+0

@KennyTM: Хорошее наблюдение. Размеры жалоб по умолчанию не входят в наши системы типов. Он поймал много ошибок. – sigfpe

ответ

0

Это ленивый ответ, но следующая страница должна иметь информацию, которую вы хотите: http://www.devmaster.net/wiki/Ray-sphere_intersection

В более общем плане, прибегая к помощи луча сферы пересечения, а не линии сферы пересечения должны дать богатый простой информации.

Кроме того, я думаю, что это по существу дубликат этого вопроса: Testing whether a line segment intersects a sphere

0

Она смотрит на меня, как вы хотите использовать вместо

inView :: Point -> Point -> Sphere -> Bool 
inView (Point x1 y1 z1) (Point x2 y2 z2) (Sphere (Point x3 y3 z3) r) 
    | result > 0 && result < r^2 = False // is this correct? I know nothing about Haskell, but seems like this should be True 
    | otherwise     = True 
    where result = -t1^2/t2 + t3 
     t1 = (x3 - x1) * (x2 - x1) + (y3 - y1) * (y2 - y1) + (z3 - z1) * (z2 - z1) 
     t2 = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1) 
     t3 = (x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1) + (z3 - z1) * (z3 - z1) 

NB. Я не знаю, что обозначение Haskell для квадрата, поэтому я использовал ^2 выше.

е: работа here и here

2

Вы используете неправильное уравнение. Если ваша линия представлена ​​как:

p1 + u (p2 - p1) 

(где u является скаляр), то top/bot находит u, что делает это выражение как можно ближе к центру сферы.

Поэтому я хотел бы изменить код:

where u = top/bot 
     nearestPoint = {- p1 + u (p2 - p1) -} 
     result = {- distance between nearestPoint and p3 -} 

заливку в этом псевдокоде, и вы должны быть золотыми. Вы просто неверно истолковали значение result.

Кстати, вы могли бы, вероятно, очистить свой код, используя Data.VectorSpace.Я могу выписать мою поправку в полном объеме легко использовать его:

import Data.VectorSpace 

type Point = (Double, Double, Double) 
inView :: Point -> Point -> Sphere -> Bool 
inView p1 p2 (Sphere p3 r) = result < r 
    where u = top/bot 
      top = ... 
      bot = ... 
      nearestPoint = p1 ^+^ u *^ (p2 ^-^ p1) 
      result = magnitude (p3 ^-^ nearestPoint) 
1

Я не знаю, если это наиболее эффективный способ сделать вещи, но одна вещь, чтобы рассмотреть:

линия пересекает сферы, если перпендикулярное расстояние от линии до центра сферы меньше или равно радиусу сферы.

Тогда возникает вопрос: как рассчитать расстояние от точки до линии?

Смежные вопросы