查找由一组线创建的平面的所有分区

时间:2017-11-24 05:22:04

标签: python matlab math wolfram-mathematica computational-geometry

我有一组线(形式为y = mx + b的线性函数)(其中120个!),如果我将它们全部绘制出来,那么它们就会对R ^ 2平面进行分区。这些线不一定要通过原点。

查找由一组此类行创建的所有分区的最有效方法是什么?就个人而言,我很难想出任何方式,更不用说有效率了。为了更清楚,我包括以下只有4行的图像:ste of lines

分区的示例是set {(x,y)|y <= -30x+28 && 5x+3 <= y <= 60x+2},它是由第一象限中的红色,黄色和绿色线创建的分区。另一个例子是{(x,y)|5x+3 <= y <= -30x+28},它是第一象限中由蓝色,红色和绿色线界定的三角形。

分区的一个示例是{(x,y)|5x+3 <= y <= -30x+28 && 90x+7 <= y},它是由上面的绿线和下面的蓝线界定的集合。这不是分区,因为其中包含多个分区(例如,上面的第二个集合),或者重叠它。但是,集合{(x,y)|y <= -30x+28 && 5x+3 <= y <= 60x+2},{(x,y)| -30x+28<= y && 60x+2 <= y <= 90x+7}...将是一个分区。

所需的输出将是此类集的完整列表: y <= 5x+3 && y >= 90x+7 && y<= -30x+28等等。当然,他们不必用这种符号表示。

我不确定如何解决这个问题,因此,遗憾的是,它无法提供我尝试过的方法。理想情况下,我想在R,Python,Mathematica或MATLAB中执行此操作,但我现在可以选择任何选项。

编辑:由于符号似乎存在问题,我会稍微澄清一下。简单地获得点上的条件列表就足够了,这样满足该条件的所有点都将精确地定义分区。例如,一长串交叉点就可以了:actions = new Actions(webDriver); IWebElement sourceelement = webDriver.FindElement(By.XPath("//*[@id=\"resizable\"]/div[3]")); actions.ClickAndHold(sourceelement).MoveByOffset(400, 400).Release(); actions.Perform(); 是定义分区的完美输出。当然,期望的输出是这种分区的完整列表(如上所定义)。

5 个答案:

答案 0 :(得分:4)

找到分区的数量遵循这个公式(当没有3条或更多条线在同一点相交时 - 这个假设贯穿这篇文章):

num_partitions = (n_lines * (n_lines + 1) / 2 ) + 1

可以找到解释here,另一个there

  

所需的输出将是此类集的完整列表:   {(x,y)|y <= -30x+28 && 5x+3 <= y <= 60x+2}, {(x,y)| -30x+28<= y && 60x+2 <= y <= 90x+7}...    等......它们不必用这种符号表示   当然。

缺乏精确的符号是这里的障碍。

以下是我对信封的尝试。如您所见,可以根据它们与每条线的相对位置来识别编号区域 有5个空集,如果行排序发生变化则不一样 用线 对平面上的一组点进行分区可能会更容易,试图确定哪个点属于哪个点;在这种情况下,探索2^n潜在分区并返回其内容将很容易。 (比试图找到一个好的符号来识别抽象集更容易)

enter image description here

这并不能完全回答你的问题,但对于能够/愿意进一步推动这一问题的人来说,这可能是一个很好的说明点。
以下是关于partitioning a set of points with two lines in the plane.的说明 这是一个不同的问题,但它的一些方法可能有用。

其他方法:

识别由线段形成的多边形,计算凸包,确定一个点是否在该船体中。

答案 1 :(得分:3)

这是Mathematica中的解决方案。该方法包括找到线交叉点,线段和分区,同时跟踪点连接的线。

y[1] = 5 x + 3;
y[2] = 90 x + 7;
y[3] = -30 x + 28;
y[4] = 60 x + 2;

findpoints[n_] := Module[{},
  xp = DeleteCases[{{First[#1], First[#2]},
       Solve[Last[#1] == Last[#2], x]} & @@@
     DeleteCases[
      Tuples[Array[{#, y[#]} &, n], 2],
      {{x_, _}, {x_, _}}], {_, {}}];
  yp = y[#[[1, 1]]] /. #[[2, 1]] & /@ xp;
  MapThread[{#1, {#2, #3}} &,
   {xp[[All, 1]], xp[[All, 2, 1, 1, 2]], yp}]]

xyp = findpoints[4];

{xmin, xmax} = Through[{Min, Max}@
    xyp[[All, 2, 1]]] + {-0.7, 0.7};

outers = Flatten[Array[Function[n,
     MapThread[List[{{n, 0}, {##}}] &,
      {{xmin, xmax}, y[n] /.
    List /@ Thread[x -> {xmin, xmax}]}]], 4], 2];

xyp = Join[outers, xyp];

findlines[p_] := Module[{},
  pt = DeleteCases[
    Cases[xyp, {{p[[1, 1]], _}, _}], p];
  n = First@Cases[pt,
     {_, First@Nearest[Last /@ pt, Last[p]]}];
  {{First[p], First[n]}, {Last[p], Last[n]}}]

lines = Map[findlines, xyp];

(* boundary lines *)
{ymin, ymax} = Through[{Min, Max}@outers[[All, 2, 2]]];
{lbtm, rbtm, ltop, rtop} = {{xmin, ymin},
   {xmax, ymin}, {xmin, ymax}, {xmax, ymax}};
xminlines = Partition[Union@Join[{ymin, ymax},
      Cases[xyp, {_, {xmin, _}}][[All, 2, 2]]], 2, 1] /.
   x_Real :> {xmin, x};
xmaxlines = Partition[Union@Join[{ymin, ymax},
      Cases[xyp, {_, {xmax, _}}][[All, 2, 2]]], 2, 1] /. 
   x_Real :> {xmax, x};
lines2 = Join[Last /@ lines, xminlines, xmaxlines,
   {{lbtm, rbtm}}, {{ltop, rtop}}];

ListLinePlot[lines2]

enter image description here

(* add vertex points *)
xyp2 = Join[xyp, {
   {{SortBy[Cases[outers, {_, {xmin, _}}],
       Last][[-1, 1, 1]], -1}, ltop},
   {{SortBy[Cases[outers, {_, {xmax, _}}],
       Last][[-1, 1, 1]], -1}, rtop},
   {{SortBy[Cases[outers, {_, {xmin, _}}],
       Last][[1, 1, 1]], -1}, lbtm},
   {{SortBy[Cases[outers, {_, {xmax, _}}],
       Last][[1, 1, 1]], -1}, rbtm}}];

anglecalc[u_, v_] := Mod[(ArcTan @@ u) - (ArcTan @@ v), 2 π]

getlineangles[] := Module[{},
  (* find the angles from current line
     to all the linked lines *)
  angle = Map[
    anglecalc[{c, d} - {g, h}, # - {g, h}] &,
    union = DeleteCases[Union@Join[
        Last /@ Cases[lines2, {{g, h}, _}],
        First /@ Cases[lines2, {_, {g, h}}]],
      {c, d}]];
  Sort[Transpose[{N@angle, union}]]]

getpolygon[pt_, dir_] := Module[{},
  Clear[p];
  p[n = 1] = {{a, b}, {c, d}} = pt;
  (* find the angles from vector (0, -1) or (0, 1)
     to all the linked lines *)

  angle = Map[anglecalc[If[dir == 1, {0, -1}, {0, 1}], # - {c, d}] &,
    union = Union@Join[
       Last /@ Cases[lines2, {{c, d}, _}],
       First /@ Cases[lines2, {_, {c, d}}]]];
  lineangles = Sort[Transpose[{N@angle, union}]];
  (* next point *)
  p[++n] = {{e, f}, {g, h}} = First@
     Cases[xyp2, {_, lineangles[[1, 2]]}];

  While[Last[p[n]] != Last[p[1]],
   lineangles = getlineangles[];
   (* reset first point *)
   {{a, b}, {c, d}} = {{e, f}, {g, h}};
   (* next point *)
   p[++n] = {{e, f}, {g, h}} = First@
      Cases[xyp2, {_, lineangles[[1, 2]]}]];

  Array[p, n]]

len = Length[xyp];

polygons = Join[Array[(poly[#] = getpolygon[xyp[[#]], 1]) &, len],
   Array[(poly[# + len] = getpolygon[xyp[[#]], 2]) &, len]];

graphics = DeleteDuplicates /@ Array[Last /@ poly[#] &, 2 len];

sortedgraphics = Sort /@ graphics;

positions = Map[Position[sortedgraphics, #] &,
    DeleteDuplicates[sortedgraphics]][[All, 1, 1]];

unique = poly /@ positions;

poly2 = unique[[All, All, 2]];

poly2 = Delete[poly2,
   Array[If[Length[Intersection[poly2[[#]],
         Last /@ Take[xyp2, -4]]] == 4, {#}, Nothing] &,
    Length[poly2]]];

len2 = Length[poly2];

poly3 = Polygon /@ Rest /@ poly2;

Array[(centroid[#] = RegionCentroid[poly3[[#]]]) &, len2];

Show[Graphics[Array[{ColorData[24][#],
     poly3[[#]]} &, len2], AspectRatio -> 1/GoldenRatio],
 Graphics[Array[Text[#, centroid[#]] &, len2]]]

enter image description here

unique2 = Extract[unique,
   Flatten[Position[unique[[All, All, 2]], #] & /@ poly2, 1]];

makerelations[oneconnection_, areanumber_] := Module[{i},
  If[Intersection @@ oneconnection == {} ||
    (i = First[Intersection @@ oneconnection]) < 1,
   Nothing,
   centroidx = First[centroid[areanumber]];
   linepos = y[i] /. x -> centroidx;
   relation = If[linepos < Last[centroid[areanumber]],
     " >= ", " < "];
   string = StringJoin["y", relation, ToString[y[i]]]]]

findrelations[n_] := Module[{},
  areanumber = n;
  onearea = unique2[[areanumber]];
  connections = Partition[First /@ onearea, 2, 1];
  strings = DeleteDuplicates@
    Map[makerelations[#, areanumber] &, connections];
  StringJoin["Area ", ToString[areanumber],
   If[areanumber > 9, ": ", ":  "],
   StringRiffle[strings, " &&\n         "]]]

Show[Plot[Evaluate@Array[y, 4], {x, -1, 1.5},
  PlotLegends -> "Expressions", Axes -> None],
 Graphics[Array[Text[#, centroid[#]] &, len2]]]

Column@Array[findrelations, len2]

enter image description here

Area 1:  y >= 28 - 30 x &&
         y < 3 + 5 x
Area 2:  y >= 2 + 60 x &&
         y >= 28 - 30 x &&
         y < 7 + 90 x
Area 3:  y < 28 - 30 x &&
         y < 7 + 90 x &&
         y < 2 + 60 x &&
         y < 3 + 5 x
Area 4:  y >= 3 + 5 x &&
         y >= 28 - 30 x &&
         y < 2 + 60 x
Area 5:  y < 3 + 5 x &&
         y >= 2 + 60 x &&
         y < 7 + 90 x
Area 6:  y < 28 - 30 x &&
         y >= 2 + 60 x &&
         y >= 3 + 5 x &&
         y < 7 + 90 x
Area 7:  y < 28 - 30 x &&
         y >= 3 + 5 x &&
         y < 2 + 60 x
Area 8:  y < 28 - 30 x &&
         y >= 7 + 90 x &&
         y >= 3 + 5 x
Area 9:  y < 2 + 60 x &&
         y >= 7 + 90 x
Area 10: y >= 28 - 30 x &&
         y >= 7 + 90 x
Area 11: y < 3 + 5 x &&
         y >= 7 + 90 x &&
         y >= 2 + 60 x

答案 2 :(得分:2)

完整的Matlab解决方案。 120行7021分区,0.4秒原始计算(绘图+2秒)。

最终

clear
tic
%rng(15) % fix rng for debug
NLines=9;
DRAW_FINAL_POLY= true==true ; %false true
DRAW_FINALTEXT= true==true ; %false true
DRAW_LINES= false==true; %false true
DRAW_DEBUG= false==true; %false true

% part a - generate lines
NORM_EPS=1e-10;
Lines=10*(rand(NLines,4)-0.5); %(x1,y1,x2,y2)
Color=rand(NLines,3);
Lines(1,:)=[-10,0,+10,0];% x axis if we want to add asix as lines
Lines(2,:)=[0,-10,0,+10];% y axis
Color(1,:)=[1,0,0];% x axis red
Color(2,:)=[0,1,0];% y axis green
Color(3,:)=[0,0,1];% third blue

AllPairs=sortrows(combnk(1:NLines,2));
NPairs=size(AllPairs,1);
[px,py,isok,d] = LineIntersection(Lines(AllPairs(:,1),:) , Lines(AllPairs(:,2),:));
% draw lines and intersections
figure(7); cla; ax=gca;axis(ax,'auto');
if DRAW_LINES
    for iline=1:size(Lines,1)
        line(ax,Lines(iline,[1 3]),Lines(iline,[2 4]),'LineWidth',2','Color',Color(iline,:)); %draw partial line defined by points x1y1x2y2
    end
    for i=1:NPairs %extraploate line to intersection point
        iline1=AllPairs(i,1);
        iline2=AllPairs(i,2);
        line(ax,[Lines(iline1,[1]),px(i)],[Lines(iline1,[2]),py(i)],'LineWidth',2','Color',Color(iline1,:));
        line(ax,[Lines(iline2,[1]),px(i)],[Lines(iline2,[2]),py(i)],'LineWidth',2','Color',Color(iline2,:));
    end
    line(ax,px,py,'LineStyle','none','Marker','*','MarkerSize',8,'Color','g');%draw intersection points
    for i=1:NPairs
        text(px(i)+0.2,py(i)+0.2,sprintf('%d',i),'FontSize',14,'Color','c')
    end
end

% part b - find regions
% 1 for each line sort all its intersections
SortIntr=cell(1,NLines); %(if no parallel lines than NintrsctnsPerline = NLines-1)
IpairiIdx1=cell(1,NLines);
IpairiIdx2=cell(1,NLines);
IpairiIdxI=cell(1,NLines);
for iline=1:NLines
    [idx1,idx2]=find(AllPairs==iline);
    intr=[px(idx1),py(idx1)];
    [~, Isortedintr]=sortrows(intr.*[1,1]); %sort by increaing x y. (prepare clockwise travers)
    SortIntr{iline}=intr(Isortedintr,:);
    IpairiIdx1{iline}=idx1(Isortedintr);
    IpairiIdx2{iline}=3-idx2(Isortedintr); %keep indexes of second line
    IpairiIdxI{iline}=Isortedintr;
end
% 2 traverse from every point and find next closest intersctionn
% we go clockwise x+x-y
PointsInPartition={};
SolIndexInPartition={};
LineIndexInPartition={};
Line4PointsInPartition={};
VisitedSequence=false(NPairs,NPairs); %skip same sequence
count_added=0; count_skipped=0;

for iline=1:NLines
    for ipoint_idx=1:length(SortIntr{iline})-1 %cant start from last point in line
        ipoint=SortIntr{iline}(ipoint_idx,:);
        if DRAW_DEBUG
            delete(findall(ax,'Tag','tmppoint'));
            line(ax,ipoint(1),ipoint(2),'LineStyle','none','Marker','O','MarkerSize',12,'Color','r','tag','tmppoint');%draw intersection points
        end
        current_line=iline;
        isol_idx=IpairiIdx1{current_line}(ipoint_idx);
        current_p_idx=ipoint_idx;
        current_l_next_p_idx=current_p_idx+1;
        next_line=AllPairs(IpairiIdx1{current_line}(current_l_next_p_idx), IpairiIdx2{current_line}(current_l_next_p_idx));
        % next_point_idx = find(IpairiIdx1{current_line}(next_point_idx)==IpairiIdx1{next_line});
        sol_idx_list=[isol_idx]; 
%       if ismember(isol_idx,[7,8,12]),keyboard;end
        point_list=[ipoint];
        line_list=[iline];
        while next_line~=iline
            if DRAW_DEBUG
                delete(findall(ax,'Tag','tmpline'));
                line(ax,Lines(current_line,[1 3]),Lines(current_line,[2 4]),'LineWidth',4','Color',[ 0,0,0 ],'Tag','tmpline');
                line(ax,Lines(next_line,[1 3]),Lines(next_line,[2 4]),'LineWidth',4','Color',[ 1,1,1 ],'Tag','tmpline');
            end
            current_sol_idx=IpairiIdx1{current_line}(current_l_next_p_idx);
            current_p_idx = find(IpairiIdx1{next_line}==current_sol_idx);
            current_line=next_line;
            current_point=SortIntr{current_line}(current_p_idx,:);
            current_nrm=norm(current_point-ipoint);
            current_o=atan2d(-current_point(2)+ipoint(2),current_point(1)-ipoint(1));

            sol_idx_list(end+1)=current_sol_idx; %#ok<SAGROW>
            point_list(end+1,:)=current_point; %#ok<SAGROW>
            line_list(end+1)=current_line;
            if DRAW_DEBUG,line(ax,current_point(1),current_point(2),'LineStyle','none','Marker','O','MarkerSize',12,'Color','m','tag','tmppoint');end %draw intersection points
            %select between two options. next clockwise point is the one with higher angle
            if current_p_idx+1<=length(SortIntr{current_line}) && current_p_idx-1>0
                next_point_1=SortIntr{current_line}(current_p_idx+1,:);
                next_point_2=SortIntr{current_line}(current_p_idx-1,:);
                if norm(next_point_1-ipoint)<NORM_EPS
                    current_l_next_p_idx=current_p_idx+1;
                elseif norm(next_point_2-ipoint)<NORM_EPS
                    current_l_next_p_idx=current_p_idx-1;
                else
                    o1=atan2d(-next_point_1(2)+ipoint(2),next_point_1(1)-ipoint(1));
                    o2=atan2d(-next_point_2(2)+ipoint(2),next_point_2(1)-ipoint(1));
                    if o1>o2
                        current_l_next_p_idx=current_p_idx+1;
                    else
                        current_l_next_p_idx=current_p_idx-1;
                    end
                end
            elseif current_p_idx-1>0
                current_l_next_p_idx=current_p_idx-1;
            else
                current_l_next_p_idx=current_p_idx+1;
            end

            next_p=SortIntr{current_line}(current_l_next_p_idx,:);
            next_o=atan2d(-next_p(2)+ipoint(2),next_p(1)-ipoint(1));
            next_nrm=norm(next_p-ipoint);
            if DRAW_DEBUG,disp([current_nrm,next_nrm,current_o,next_o]);end
            next_line=AllPairs(IpairiIdx1{current_line}(current_l_next_p_idx), IpairiIdx2{current_line}(current_l_next_p_idx));
            next_sol_idx=IpairiIdx1{current_line}(current_l_next_p_idx);
            if VisitedSequence(current_sol_idx,next_sol_idx)
                next_line=-2;
                if DRAW_DEBUG,disp('seq visited');end
                break;
            end
            if next_nrm>NORM_EPS && next_o<current_o || next_o-current_o>180
                next_line=-2;
                if DRAW_DEBUG,disp('next_o<current_o');end
                break; %non clockwise
            end
            assert(next_nrm<NORM_EPS && next_line==iline || next_nrm>=NORM_EPS && next_line~=iline);
        end

        if next_line==iline
            sol_idx_list(end+1)=next_sol_idx; %#ok<SAGROW>
            point_list(end+1,:)=next_p; %#ok<SAGROW>
            PointsInPartition{end+1}=point_list; %#ok<SAGROW>
            SolIndexInPartition{end+1}=sol_idx_list; %#ok<SAGROW>
            %Line4PointsInPartition{end+1}=(Lines(AllPairs(sol_idx_list,1),:), [1; 0])+kron(Lines(AllPairs(sol_idx_list,2),:), [0; 1]);%#ok<SAGROW>
            Line4PointsInPartition{end+1}=Lines(line_list,:);%#ok<SAGROW>

            for i=1:length(sol_idx_list)-1
                VisitedSequence(sol_idx_list(i),sol_idx_list(i+1))=true;
            end
            count_added=count_added+1;
        else
            count_skipped=count_skipped+1;
        end
        if DRAW_DEBUG, disp([next_line==iline, count_added,count_skipped]);end
    end
end

% draw all segments
if DRAW_DEBUG %clear debug
    delete(findall(ax,'Tag','tmppoint'));
    delete(findall(ax,'Tag','tmpline'));
end
NPartition=length(PointsInPartition);
s=sprintf('Lines=%d, Segments=%d, RunTime=%1.2fsec',NLines,NPartition,toc);
title(ax,s);
fprintf([s,newline]);
if DRAW_FINAL_POLY
    hold(ax,'on');
    for i=1:NPartition
        plist=PointsInPartition{i};
        patch(plist(:,1),plist(:,2),i,'FaceAlpha',.3)
        [cx,cy]=ploygon_centroid(plist(:,1),plist(:,2));
        if(DRAW_FINALTEXT),text(cx,cy,sprintf('%d',i),'FontSize',12,'Color','k');end
    end
end

function [px,py,isok,d] = LineIntersection(Line1, Line2)
    %Line1=[x1,y1,x2,y2] Line2=[x3,y3,x4,y4]
    x1=Line1(:,1); y1=Line1(:,2); x2=Line1(:,3); y2=Line1(:,4);
    x3=Line2(:,1); y3=Line2(:,2); x4=Line2(:,3); y4=Line2(:,4);
    d=(x1-x2).*(y3-y4)-(y1-y2).*(x3-x4);%determinant
    px0=(x1.*y2-y1.*x2).*(x3-x4)-(x1-x2).*(x3.*y4-y3.*x4);
    py0=(x1.*y2-y1.*x2).*(y3-y4)-(y1-y2).*(x3.*y4-y3.*x4);
    isok=abs(d)>1e-6;
    px=px0./d;
    py=py0./d;
end

function [xc,yc] = ploygon_centroid(x,y)
    xs = circshift(x,-1);
    ys = circshift(y,-1);
    area = 0.5*sum (x.*ys-xs.*y);
    xc = sum((x.*ys-xs.*y).*(x+xs))/(6*area);
    yc = sum((x.*ys-xs.*y).*(y+ys))/(6*area);
end

Result of random 5 lines 8 lines

答案 3 :(得分:1)

编辑使用itertools的新解决方案。以下旧解决方案。 使用python包itertools,我相信这个解决方案比原始解决方案更快。然而,它仍然非常缓慢,并且超过大约20-ah线是不可行的。对于120行,这些都不会终止。

import itertools

strings = ["<=", ">="]

fxs = ["5x + 3", "-60x + 7", ...]

parts = []

if __name__ == "__main__":
    print(len(fxs))
    out = itertools.product(strings, repeat=len(fxs))
    for i in out:
        curpart = ""
        for j in range(len(i)):
            print(curpart)
            if j != len(i):
                curpart = curpart + "y " + i[j] + fxs[j] + " && "
            else:
                curpart = curpart + "y " + i[j] + fxs[j]
        parts.append(curpart)
    print(parts)

旧解决方案

这是最终为我工作的东西,在python:

fxs = [list of functions as strings, ex: "5x+3","6x+4"... etc.]

parts = []


if __name__ == "__main__":
    for f in fxs:
        fhalf = "y >= " + f
        shalf = "y <= " + f
        if len(parts) == 0:
            parts.append(fhalf)
            parts.append(shalf)
        else:
            parts1 = [s + " && " + fhalf for s in parts]
            parts2 = [s + " && " + shalf for s in parts]
            parts = parts1 + parts2
    print(parts)

对于上面的例子,这输出:

['y >= 5x+3 && y >= 90x+7 && y >= -30x+28 && y >= 60x+2', 'y <= 5x+3 && y >= 90x+7 && y >= -30x+28 && y >= 60x+2', 'y >= 5x+3 && y <= 90x+7 && y >= -30x+28 && y >= 60x+2', 'y <= 5x+3 && y <= 90x+7 && y >= -30x+28 && y >= 60x+2', 'y >= 5x+3 && y >= 90x+7 && y <= -30x+28 && y >= 60x+2', 'y <= 5x+3 && y >= 90x+7 && y <= -30x+28 && y >= 60x+2', 'y >= 5x+3 && y <= 90x+7 && y <= -30x+28 && y >= 60x+2', 'y <= 5x+3 && y <= 90x+7 && y <= -30x+28 && y >= 60x+2', 'y >= 5x+3 && y >= 90x+7 && y >= -30x+28 && y <= 60x+2', 'y <= 5x+3 && y >= 90x+7 && y >= -30x+28 && y <= 60x+2', 'y >= 5x+3 && y <= 90x+7 && y >= -30x+28 && y <= 60x+2', 'y <= 5x+3 && y <= 90x+7 && y >= -30x+28 && y <= 60x+2', 'y >= 5x+3 && y >= 90x+7 && y <= -30x+28 && y <= 60x+2', 'y <= 5x+3 && y >= 90x+7 && y <= -30x+28 && y <= 60x+2', 'y >= 5x+3 && y <= 90x+7 && y <= -30x+28 && y <= 60x+2', 'y <= 5x+3 && y <= 90x+7 && y <= -30x+28 && y <= 60x+2']

代码非常简单,输出完全符合要求。

这个想法基本上是每条线将平面分成两半,所以循环(迭代在一组线上)与每一半已找到的每个分区相交,并将两个新分区添加到集合中,同时删除原始的交叉分区。结果并不总是给出最简单的条件(某些条件可能是多余的),但它们确实给出了每个分区的完整描述。

虽然这个解决方案可行,但有120行,但速度很慢。我有兴趣看看是否有更有效的方法来实现这一点,使用这种方法或其他方式。

答案 4 :(得分:0)

到目前为止建议的另一种方法是使用三角形。

从一组三角形(可能包含无限远点)开始,其联合是覆盖整个平面的多边形。例如,您可以开始将四个三角形分开,其中前两行作为算法的输入,或者采用由原点O形成的三个三角形,即OX轴的正侧,以及两个半与OX形成120度和240度的线,也从O开始。

现在,对于作为输入给出的每一行,你去寻找它所穿过的三角形,并且对于每一行,你在与该线的交点处切割它并将其替换为三个(或两个在退化情况下)新三角形覆盖同一地区。然后你必须找到那些旧的相交三角形所在的多边形,然后用两个多边形替换每一个多边形,这样就可以根据它们所在线的一边分割它所包含的三角形。

使用三角形的好处在于它使计算变得更加容易,并且您可以在某些索引数据结构(例如kd树)中推送,这样可以更快地计算哪些多边形被某条线切割,并且您可以以复杂度O(NlogN)的算法结束,其中N是形成平面分区的多边形数。