存在許多問題,已經涵蓋如何檢測線段和圓之間的碰撞。Matlab - 用於檢測線段和圓之間的碰撞的函數失敗
在我的代碼,我使用Matlab的linecirc
功能,然後比較它與我的線段的端部返回的交叉點,以檢查點是線內(linecirc假定無限線,我不沒有/想要)。
複製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
調用顯示函數計數的位置。 實施if(p1OnSeg == 1)
塊內sprintf
呼叫指示我的功能已選擇虛擬交叉點(雖然它然後與他們正確處理)
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]
甲圖爲奇怪點。
對不起,很長的問題,但 - 在這些被檢測的原因。它們不在圓上(顯示mylinecirc
函數中的值可以檢測交點在(-25,55)和(-25,-55)左右(如無限長線所預期的那樣)
正在移動圈子可以刪除這些點,但有時這會導致其他問題的檢測這是怎麼回事
編輯:?旋轉我的格子圖案由[Vx, Vy] = voronoi(...)
創建,然後刪除點具有非常大的值(即那些去接近無窮大等)似乎已經解決了這個問題,爲了避免出現在「斜率」和「截距」中的NaN值,「大」值點的去除似乎是必要的,我的猜測是這與可能的輕微傾斜有關。旋轉,再加上期望的攔截溢出。
添加的示例代碼如下。我也在Jan de Gier的代碼中進行了編輯,但是這對問題沒有任何影響,因此在問題代碼中沒有更改。
%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,但由於傳遞給這個函數的值是「應該」(雖然更好的安全比遺憾,所以改爲你的函數)是點在相同的截距和斜率的無限線,如果該點是在矩形內,也就行 – chrisb2244 2014-09-29 06:15:03
在再現的問題而言,調用'CC = getCutCountHex(30, [0,0])給出了錯誤的答案,但是......(33,[0,0])產生了圖中可見的8個交點 – chrisb2244 2014-09-29 06:16:10