2014-09-26 11 views
4

Существует много вопросов, которые уже касаются обнаружения столкновений между сегментом линии и кругом.Matlab - Ошибки функции для обнаружения столкновений между отрезками линии и окружности

В моем коде я использую функцию Matlab linecirc, а затем сравнивая точки пересечения, которые он возвращает с концами моих отрезков, чтобы проверить, что точки находятся внутри линии (linecirc принимает бесконечную линию, t есть/хотите).

Копирование и добавление некоторых сообщений sprintf на функцию linecirc показывает, что она вычисляет точки, как предполагалось. Кажется, что мои функции теряются.

Мой код ниже:

function cutCount = getCutCountHex(R_g, centre) 
clf; 
cutCount = 0; 

% Generate a hex grid 
Dg = R_g*2; 
L_b = 62; 

range = L_b*8; 

dx = Dg*cosd(30); 
dy = 3*R_g; 
xMax = ceil(range/dx); yMax = ceil(range/dy); 
d1 = @(xc, yc) [dx*xc dy*yc]; 
d2 = @(xc, yc) [dx*(xc+0.5) dy*(yc+0.5)]; 

centres = zeros((xMax*yMax),2); 
count = 1; 

for yc = 0:yMax-1 
    for xc = 0:xMax-1 
     centres(count,:) = d1(xc, yc); 
     count = count + 1; 
     centres(count, :) = d2(xc, yc); 
     count = count + 1; 
    end 
end 

for i=1:size(centres,1) 
    centres(i,:) = centres(i,:) - [xMax/2 * dx, yMax/2 * dy]; 
end 

hold on 
axis equal 

% Get counter for intersected lines 
[VertexX, VertexY] = voronoi(centres(:,1), centres(:,2)); 
numLines = size(VertexX, 2); 
for lc = 1:numLines 
    segStartPt = [VertexX(1,lc) VertexY(1,lc)]; 
    segEndPt = [VertexX(2,lc) VertexY(2,lc)]; 
    slope = (segEndPt(2) - segStartPt(2))/(segEndPt(1) - segStartPt(1)); 
    intercept = segEndPt(2) - (slope*segEndPt(1)); 
    testSlope = isinf(slope); 
    if (testSlope(1)==1) 
     % Pass the x-axis intercept instead 
     intercept = segStartPt(1); 
    end 
    [xInterceptionPoints, yInterceptionPoints] = ... 
     linecirc(slope, intercept, centre(1), centre(2), L_b); 

    testArr = isnan(xInterceptionPoints); 
    if (testArr(1) == 0) % Line intersects. Line segment may not. 
     interceptionPoint1 = [xInterceptionPoints(1), yInterceptionPoints(1)]; 
     interceptionPoint2 = [xInterceptionPoints(2), yInterceptionPoints(2)]; 

     % Test if first intersection is on the line segment 
     p1OnSeg = onSeg(segStartPt, segEndPt, interceptionPoint1); 
     p2OnSeg = onSeg(segStartPt, segEndPt, interceptionPoint2); 
     if (p1OnSeg == 1) 
      cutCount = cutCount + 1; 
      scatter(interceptionPoint1(1), interceptionPoint1(2), 60, 'MarkerFaceColor', 'r', 'MarkerEdgeColor', 'k'); 
     end 

     % Test if second intersection point is on the line segment 
     if (interceptionPoint1(1) ~= interceptionPoint2(1) || interceptionPoint1(2) ~= interceptionPoint2(2)) % Don't double count touching points 
      if (p2OnSeg == 1) 
       cutCount = cutCount + 1; 
       scatter(interceptionPoint2(1), interceptionPoint2(2), 60, 'MarkerFaceColor', 'r', 'MarkerEdgeColor', 'k'); 
      end 
     end 
    end 
end 

% Plot circle 

viscircles(centre, L_b, 'EdgeColor', 'b'); 
H = voronoi(centres(:,1), centres(:,2)); 
for i = 1:size(H) 
    set(H(i), 'Color', 'g'); 
end 
end 

function boolVal = onSeg(segStart, segEnd, testPoint) 
bvX = isBetweenOrEq(segStart(1), segEnd(1), testPoint(1)); 
bvY = isBetweenOrEq(segStart(2), segEnd(2), testPoint(2)); 
if (bvX == 1 && bvY == 1) 
    boolVal = 1; 
else 
    boolVal = 0; 
end 
end 

function boolVal = isBetweenOrEq(end1, end2, test) 
    if ((test <= end1 && test >= end2) || (test >= end1 && test <= end2)) 
     boolVal = 1; 
    else 
     boolVal = 0; 
    end 
end 

Это создает гексагональную сетку, а затем вычисляет количество пересечений между окружности, проведенной с фиксированным радиусом (62 в данном случае) и указанным центром.

Звонки scatter показывают местоположения, в которых функция рассчитывает. Реализация sprintf звонки внутри if(p1OnSeg == 1) блока указывает на то, что моя функция выбрал фиктивные точки пересечения (хотя тогда дело с ними правильно)

if (interceptionPoint1(1) > -26 && interceptionPoint1(1) < -25) 
       sprintf('p1 = [%f, %f]. Vx = [%f, %f], Vy = [%f, %f].\nxint = [%f, %f], yint = [%f, %f]',... 
        interceptionPoint1(1), interceptionPoint1(2), VertexX(1,lc), VertexX(2,lc), VertexY(1,lc), VertexY(2,lc),... 
        xInterceptionPoints(1), xInterceptionPoints(2), yInterceptionPoints(1), yInterceptionPoints(2)) 
      end 

Выходы

p1 = [-25.980762, 0.000000]. Vx = [-25.980762, -25.980762], Vy = [-15.000000, 15.000000]. 
xint = [-25.980762, -25.980762], yint = [0.000000, 0.000000] 

Картина показывает странные моменты.

enter image description here

Извините за очень длинный вопрос, но - почему они обнаруживаются. Они не лежат на круге (отображение значений внутри функции обнаруживает пересечения вокруг (-25, 55) и (-25, -55) или так (как ожидала бесконечная линия).

Перемещение круг может удалить эти точки, но иногда это приводит к возникновению других проблем с обнаружением Что сделка

Edit:.? Вращающийся мой образец сетки, созданный [Vx, Vy] = voronoi(...) и затем удаляя точки с очень большими значениями (т.е. тех, которые идут рядом с бесконечность и т. д.) устраняет эту проблему. Удаление «больших» значений кажется необходимым, чтобы избежать появления значений NaN в «наклоне» и «перехвате». Я предполагаю, что это связано с возможным небольшим наклоном из-за t o вращение, в сочетании с последующим переполнением ожидаемого перехвата.

Ниже приведен пример кода. Я также редактировал код Ян де Гира, но это не имело никакого отношения к проблеме и поэтому не менялось в вопросительном коде.

%Rotate slightly 
RotAngle = 8; 
RotMat = [cosd(RotAngle), -sind(RotAngle); sind(RotAngle), cosd(RotAngle)]; 

for i=1:size(centres,1) 
    centres(i,:) = centres(i,:) - [floor(xMax/2) * dx, floor(yMax/2) * dy]; %Translation 
    centres(i,:) = (RotMat * centres(i,:)'); %Rotation 
end 


% Get counter for intersected lines 
[VertexX, VertexY] = voronoi(centres(:,1), centres(:,2)); 

% Filter vertices 
numLines = size(VertexX, 2); 
newVx = []; 
newVy = []; 
for lc = 1:numLines 
    testVec = [VertexX(:,lc) VertexY(:,lc)]; 
    if ~any(abs(testVec) > range*1.5) 
     newVx = [newVx; VertexX(:,lc)']; 
     newVy = [newVy; VertexY(:,lc)']; 
    end 
end 
VertexX = newVx'; 
VertexY = newVy'; 
numLines = size(VertexX, 2); 

По-прежнему ценим ответы или предложения, чтобы выяснить, почему это происходит. Примеры значений, которые вызывают это являются getCutCountHex(30, [0,0]) и ...(35, [0,0])

ответ

1

Я не могу воспроизвести вашу проблему, но то, что я заметил, что ваша функция onSeg() может быть неправильно: он возвращает истину, если тестпоинт лежит в прямоугольнике с двумя четыре угловых точки - segStart и segEnd.

функция, которая возвращает истину, если и только если точка находится на (или более точно: достаточно близко) отрезок (segStart, segEnd) может быть:

function boolVal = onSeg(segStart, segEnd, testPoint) 

    tolerance = .5; 

    AB = sqrt((segEnd(1)-segStart(1))*(segEnd(1)-segStart(1))+(segEnd(2)-segStart(2))*(segEnd(2)-segStart(2))); 
    AP = sqrt((testPoint(1)-segEnd(1))*(testPoint(1)-segEnd(1))+(testPoint(2)-segEnd(2))*(testPoint(2)-segEnd(2))); 
    PB = sqrt((segStart(1)-testPoint(1))*(segStart(1)-testPoint(1))+(segStart(2)-testPoint(2))*(segStart(2)-testPoint(2))); 

    boolVal = abs(AB - (AP + PB)) < tolerance; 

end 

подход, который я нашел в одном из anwers здесь: Find if point lays on line segment. Надеюсь, это решит вашу проблему.

+1

Вы правы, что это более точная оценка того, находится ли точка в сегменте линии, так что +1, но поскольку значения, переданные этой функции, являются «предполагаемыми» (хотя лучше быть в безопасности, чем извиняться , поэтому изменилась на вашу функцию), чтобы быть точками на бесконечной линии одного и того же перехвата и градиента, если точка находится внутри прямоугольника, она также находится на линии – chrisb2244

+0

С точки зрения воспроизведения проблемы вызывается 'cc = getCutCountHex (30, [0,0]) 'дает неправильные ответы, но' ... (33, [0,0]) 'создает 8 пересечений, которые видны на рисунке – chrisb2244