我有一系列细分:
ISegment[] segments
由界面定义:
public interface ISegment
{
Point3D A { get; } // Segment start point
Point3D B { get; } // Segment end point
}
可以包含以下实例:
public class Line : ISegment
{
public Point3D A { get; } // Line start point
public Point3D B { get; } // Line end point
/* ... Other line properties & methods ... */
}
或实例:
public class Arc : ISegment
{
public Point3D A { get; } // Arc start point
public Point3D B { get; } // Arc end point
/* ... Other arc properties & methods ... */
}
我正在寻找一种优雅的算法来将它们识别为细分链:
ISegment[][] segmentChains
结果如下:
[[s1, s2, s3, s4], [s5, s6], [s7], [s8, s9, s10], [s11, s12]]
没有任何订单考虑。
注意:
segments
可以有任何顺序segmentChains
可以有任何顺序欢迎提供一些帮助!
答案 0 :(得分:2)
我有一个应该有效的迭代方法。但不确定它有多优雅。我更喜欢使用Lists
而不是Arrays
,因为它们可以动态扩展(初始化时没有大小要求)。
方法签名如下:
public static List<List<ISegment>>GetSegmentChains(List<ISegment> segments)
其中segments
是段列表,返回值是“链”列表,其中每个链都是段列表。
该方法的基本思想是:
这是一种可以做到的方式:
public static List<List<ISegment>>GetSegmentChains(List<ISegment> segments)
{
// Some quick 'fail fast' validation
var segmentChains = new List<List<ISegment>>();
if (segments == null) return segmentChains;
if (segments.Count == 0) return segmentChains;
if (segments.Count == 1)
{
if (IsSingleSegmentChain(segments[0])) segmentChains.Add(segments);
return segmentChains;
}
// Get a copy of our segments
var candidateSegments = segments.ToList();
// Process each one
while (candidateSegments.Any())
{
// Remove the first one from the candidate list and add it to a temporary chain
// list, and add it's endPoints to a list for comparision with other candidates
var candidateSegment = candidateSegments.First();
candidateSegments.Remove(candidateSegment);
var candidateChain = new List<ISegment> { candidateSegment };
var endPoints = new List<Point3D> {candidateSegment.A, candidateSegment.B};
// Go through the points list, finding any candidates with a match
while (endPoints.Any())
{
foreach (var endPoint in endPoints.ToList())
{
// Add the 'other' point to our points list from each
// candidate that has a match with this point
foreach (var candidate in candidateSegments
.Where(c => ContainsPoint(c, endPoint)).ToList())
{
endPoints.Add(GetNonMatchingPoint(candidate, endPoint));
candidateSegments.Remove(candidate);
candidateChain.Add(candidate);
}
// Remove this point since it's been fully processed
endPoints.Remove(endPoint);
}
}
// See if we have a chain, and if so, add it to our return list
if (candidateChain.Count == 1 && IsSingleSegmentChain(candidateChain[0]) ||
candidateChain.Count > 1)
{
segmentChains.Add(candidateChain);
}
}
return segmentChains;
}
类修改以包含构造函数和ToString()
覆盖
public interface ISegment
{
string Name { get; }
Point3D A { get; }
Point3D B { get; }
}
public class Line : ISegment
{
public string Name { get; }
public Point3D A { get; }
public Point3D B { get; }
public Line(string name, Point3D a, Point3D b)
{
Name = name;
A = a;
B = b;
}
public override string ToString()
{
return Name;
}
}
public class Arc : ISegment
{
public string Name { get; }
public Point3D A { get; }
public Point3D B { get; }
public Arc(string name, Point3D singlePoint) : this(name, singlePoint, singlePoint)
{
}
public Arc(string name, Point3D a, Point3D b)
{
Name = name;
A = a;
B = b;
}
public override string ToString()
{
return Name;
}
}
帮助方法生成示例中的细分列表,以确定细分是否为单段链,以确定细分是否包含某个点,并获得不匹配从细分中指出:
public static List<ISegment> GenerateSegmentList()
{
// Generate the points in the diagram
var A = new Point3D(0, 0, 0);
var B = new Point3D(0, 0, 1);
var C = new Point3D(0, 0, 2);
var D = new Point3D(0, 0, 3);
var E = new Point3D(0, 0, 4);
var F = new Point3D(0, 0, 5);
var G = new Point3D(0, 0, 6);
var H = new Point3D(0, 0, 7);
var I = new Point3D(0, 0, 8);
var J = new Point3D(0, 0, 9);
var K = new Point3D(0, 1, 0);
var L = new Point3D(0, 1, 1);
var M = new Point3D(0, 1, 2);
var N = new Point3D(0, 1, 3);
// Generate the segments in the diagram
return new List<ISegment>
{
new Line("s1", A, B),
new Line("s2", B, C),
new Line("s3", C, D),
new Line("s4", D, E),
new Line("s5", F, G),
new Line("s6", G, H),
new Arc("s7", I),
new Line("s8", J, K),
new Line("s9", K, L),
new Line("s10", L, J),
new Line("s11", M, N),
new Arc("s12", N, M)
};
}
public static bool IsSingleSegmentChain(ISegment segment)
{
return segment != null && segment.A == segment.B;
}
public static bool ContainsPoint(ISegment segment, Point3D pointToMatch)
{
return segment != null && (segment.A == pointToMatch || segment.B == pointToMatch);
}
public static Point3D GetNonMatchingPoint(ISegment segment, Point3D pointToMatch)
{
return segment == null
? default(Point3D)
: (segment.A == pointToMatch)
? segment.B
: segment.A;
}
使用示例
private static void Main()
{
List<ISegment> segments = GenerateSegmentList();
List<List<ISegment>> segmentChains = GetSegmentChains(segments);
for(int i = 0; i < segmentChains.Count; i++)
{
Console.WriteLine($"Segment Chain #{i + 1}: {string.Join(" => ", segmentChains[i])}");
}
Console.WriteLine("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
<强>输出强>
答案 1 :(得分:1)
我认为,以下内容应该有效:
F
,其中起点是一个键,此时开始的Dictionary
段是一个值。