void Start() { WallManager.Instance.Register(this); var localToWorld = transform.localToWorldMatrix; var mesh = GetComponent <MeshFilter>().mesh; Vector3[] vertices = mesh.vertices; var triangles = mesh.triangles; //找到贴紧地面的那些三角形 for (int i = 0; i < triangles.Length; i += 3) { var v0 = localToWorld.MultiplyPoint(vertices[triangles[i]]); var v1 = localToWorld.MultiplyPoint(vertices[triangles[i + 1]]); var v2 = localToWorld.MultiplyPoint(vertices[triangles[i + 2]]); if (Mathf.Abs(v0.y) < k_epsilon && Mathf.Abs(v1.y) < k_epsilon && Mathf.Abs(v2.y) < k_epsilon) { var list = new List <IntPoint>(); m_polygons.Add(list); list.Add(ClipperUtils.Convert(v0)); list.Add(ClipperUtils.Convert(v1)); list.Add(ClipperUtils.Convert(v2)); } } //去掉重复的顶点 m_polygons = Clipper.SimplifyPolygons(m_polygons); }
/// <summary> /// 生成轮廓线 /// </summary> private void MakeContourLine(List <IntPoint> polygon, Vector2 hitPos) { //调整起点 var list = ClipperUtils.Convert(polygon, k_altitude); Vector2 minIntersect; int minIndex; FindStartPos(list, hitPos, out minIndex, out minIntersect); m_contour = new Vector3[list.Length + 2]; int index = 0; m_contour[index++] = new Vector3(minIntersect.x, k_altitude, minIntersect.y); for (int i = minIndex; i < list.Length; i++) { m_contour[index++] = list[i]; } for (int i = 0; i < minIndex; i++) { m_contour[index++] = list[i]; } m_contour[index++] = m_contour[0]; //首尾相连 //设置LineRenderer var line = Instantiate(m_contourLine); line.transform.SetParent(transform); line.transform.position = Vector3.zero; line.positionCount = m_contour.Length; line.SetPositions(m_contour); }
public List <IntPoint> AroundWall(Vector2 containPoint, float offset) { //将相邻的障碍物轮廓合并在一起 List <List <IntPoint> > unions = new List <List <IntPoint> >(); Clipper clipper = new Clipper(); for (int i = 0; i < m_walls.Count; i++) { clipper.AddPolygons(m_walls[i].m_polygons, PolyType.ptSubject); } if (!clipper.Execute(ClipType.ctUnion, unions)) { Debug.LogError("无法合并顶点"); return(null); } //过滤出特定的那个轮廓 List <IntPoint> contour = null; for (int i = 0; i < unions.Count; i++) { if (ClipperUtils.IsPointOnPolygonEdge(containPoint, unions[i])) { contour = unions[i]; break; } } if (contour == null) { Debug.LogError("没找到包含特定点的障碍轮廓"); return(null); } //对轮廓进行偏移 List <List <IntPoint> > result = new List <List <IntPoint> >() { contour }; result = Clipper.OffsetPolygons(result, offset * ClipperUtils.k_precision); if (result.Count > 1) { Debug.LogError("轮廓偏移后产生多个轮廓了?"); return(result[0]); } else if (result.Count == 0) { Debug.LogError("轮廓偏移后不产生轮廓了?"); return(null); } else { return(result[0]); } }
private static void CreateApartments(InDoorGeneratorSettings settings, Floor floor, List <IntPoint> footprint, List <List <IntPoint> > transitArea, List <Wall> connected) { var extrudedPolygons = new List <List <IntPoint> >(4); settings.Clipper.AddPaths(transitArea, PolyType.ptClip, true); settings.Clipper.AddPath(footprint, PolyType.ptSubject, true); settings.Clipper.Execute(ClipType.ctDifference, extrudedPolygons); settings.Clipper.Clear(); //SVGBuilder.SaveToFile(extrudedPolygons, "regions_ex.svg", 0.01, 100); foreach (var extrudedPolygon in extrudedPolygons) { // Clipper may produce small polygons on building offsets if (Clipper.Area(extrudedPolygon) / DoubleScale < settings.MinimalArea) { continue; } var firstOuterWallIndex = InvalidIndex; var firstTransitWallIndex = InvalidIndex; var outerWallCount = 0; double outerWallLength = 0; var extrudedWalls = new List <Wall>(); var lastItemIndex = extrudedPolygon.Count - 1; var mergePoint = Vector2d.Empty; double skippedDistance = 0; for (var i = 0; i <= lastItemIndex; i++) { var start = extrudedPolygon[i]; var end = extrudedPolygon[i == lastItemIndex ? 0 : i + 1]; var isOuterWall = ClipperUtils.CalcMinDistance(start, footprint) < IntPrecisionError && ClipperUtils.CalcMinDistance(end, footprint) < IntPrecisionError; var p1 = new Vector2d(start.X / Scale, start.Y / Scale); var p2 = new Vector2d(end.X / Scale, end.Y / Scale); // NOTE this allows to skip artifacts of clipper offset library // which I don't know to avoid by clipper API. var distance = p1.DistanceTo(p2); if (distance < settings.HalfTransitAreaWidth && skippedDistance < settings.TransitAreaWidth) { skippedDistance += distance; if (mergePoint != Vector2d.Empty) { continue; } mergePoint = p1; continue; } if (mergePoint != Vector2d.Empty) { p1 = mergePoint; mergePoint = Vector2d.Empty; skippedDistance = 0; } if (isOuterWall) { outerWallCount++; outerWallLength += ClipperUtils.Distance(start, end) / Scale; if (firstOuterWallIndex == InvalidIndex) { firstOuterWallIndex = extrudedWalls.Count; } } if (!isOuterWall && firstTransitWallIndex == InvalidIndex) { firstTransitWallIndex = extrudedWalls.Count; } extrudedWalls.Add(new Wall(p1, p2, isOuterWall)); } firstOuterWallIndex = firstOuterWallIndex != 0 ? firstOuterWallIndex : firstTransitWallIndex + extrudedWalls.Count - outerWallCount; var context = new FloorContext(outerWallCount, extrudedWalls.Count - outerWallCount, firstOuterWallIndex, firstTransitWallIndex); CreateAparments(settings, floor, context, extrudedWalls, connected, outerWallLength); } }