gpt4 book ai didi

Matlab - 检测线段和圆之间碰撞的功能失败

转载 作者:太空宇宙 更新时间:2023-11-03 20:06:41 25 4
gpt4 key购买 nike

许多问题已经涉及如何检测线段和圆之间的碰撞。

在我的代码中,我使用了 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) block 中实现 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]

一张图展示了奇怪的点。

enter image description here

很抱歉这个问题很长 - 为什么要检测到这些。它们不在圆上(在 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])

最佳答案

我无法重现您的问题,但我确实注意到您的 onSeg() 函数可能是错误的:如果测试点位于四个角点中的两个角点为 segStart 和 segEnd 的矩形内,它会返回 true。

如果点位于(或更准确:足够接近)线段 (segStart,segEnd) 上,则返回 true 的函数可能是:

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

我在这里的一个答案中找到了一种方法:Find if point lays on line segment .我希望这能解决您的问题。

关于Matlab - 检测线段和圆之间碰撞的功能失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26056588/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com