public void FillInsideWithFootprints() { ClearUnmodifiedFootprints(false); //List<Footprint> instantiatedFootprints = new List<Footprint>(); Vector3 bPos; Quaternion bRot; Vector3 closestPoint; //GameObject footprintObj; Footprint footprint; Primitive primitive = graph.mainPrimitives[0]; List <Node> nodes = primitive.nodes; List <Edge> edges = primitive.edges; int failedPosCount = 0; int failedPosMax = 1000; int safeCount = 0; Vector3 point; Vector3 pointWorld; while (failedPosCount < failedPosMax && safeCount < 1000) { safeCount++; //Get random point inside the boundaries float randX = UnityEngine.Random.Range(primitive.minX, primitive.maxX); float randZ = UnityEngine.Random.Range(primitive.minZ, primitive.maxZ); point = new Vector3(randX, 0f, randZ); //If point is inside the polygon, proceed if (EdgeGraphUtility.PointIsInside(point, nodes, edges)) { pointWorld = transform.TransformPoint(point); int footprintIdx = GetRandomInsideFootPrintIdx(); GetFootprintPosAndRotAtTarget(pointWorld, out bPos, out bRot, out closestPoint, footprintIdx, false); footprint = UtilityTools.Helper.GetComponentInPrefabChildren <Footprint>(footprintPrefabsOnEdge[footprintIdx]); Matrix4x4 footprintTRSMatrix = Matrix4x4.TRS(bPos, bRot, Vector3.one); if (!FootprintOverlapsOthers(footprint, footprintTRSMatrix) && FootprintIsInsideGraph(footprint, footprintTRSMatrix)) { PlaceFootprint(bPos, bRot, footprintIdx, false); } else { failedPosCount++; } } if (failedPosCount >= failedPosMax || safeCount >= 1000) { break; } } }
/// <summary> /// Gets position and rotation in given target position according to closest edge /// </summary> /// <param name="target"></param> /// <param name="pos"></param> /// <param name="rot"></param> /// <param name="index"></param> /// <param name="placeInside">Is footprint placed inside or outside the edge?</param> /// <param name="placeOnEdge">Is footprint placed on the edge or on target?</param> public void GetFootprintPosAndRotAtTarget(Vector3 target, out Vector3 pos, out Quaternion rot, out Vector3 closestPoint, int index, bool placeOnEdge = true, bool placeInside = true) { pos = Vector3.zero; rot = Quaternion.identity; closestPoint = Vector3.zero; if (placeOnEdge) { // Line the footprint with closest edge Edge edge = null; closestPoint = EdgeGraphUtility.GetClosestPointOnEdge(target, graph.mainPrimitives[0].nodes, graph.mainPrimitives[0].edges, transform, out edge); Node n1 = EdgeGraphUtility.GetNode(edge.Node1, ref graph.mainPrimitives[0].nodes); Vector3 eN1Pos = n1.Position; Vector3 eN2Pos = EdgeGraphUtility.GetNode(edge.Node2, ref graph.mainPrimitives[0].nodes).Position; eN2Pos.y = eN1Pos.y; Footprint fp = UtilityTools.Helper.GetComponentInPrefabChildren <Footprint>(footprintPrefabsOnEdge[index]); if (fp != null) { Vector3 fpN1Pos = fp.nodes[0].Position; Vector3 fpN2Pos = fp.nodes[1].Position; Vector3 fpEdgePoint = Edge.GetClosestPointOnEdge(Vector3.zero, fpN1Pos, fpN2Pos); //Vector3 nodeDir = (fpN2Pos - fpN1Pos).normalized; Vector3 edgeDir = (eN2Pos - eN1Pos).normalized; Vector3 edgeNormal = UtilityTools.MathHelper.LeftSideNormal(edgeDir); // Check that edge normal points outside (building will be placed inside the edge) if (Vector3.Dot(n1.dirToInside, edgeNormal) > 0) { edgeNormal = -edgeNormal; } // Place the building outside if (!placeInside) { edgeNormal = -edgeNormal; } pos = closestPoint - edgeNormal * (fpEdgePoint.magnitude + .05f); rot = Quaternion.LookRotation((pos - closestPoint), Vector3.up); } else { Debug.Log("FootprintPlacer::GetFootprintPosAndRotAtTarget() - No footprint found in prefab."); } } else { pos = target; rot = Quaternion.AngleAxis(Random.Range(0f, 360f), Vector3.up); } }
bool FootprintIsInsideGraph(Footprint footprint, Matrix4x4 footprintTRSMatrix) { for (int i = 0; i < footprint.edges.Count; i++) { Vector3 n1PosWorld = footprintTRSMatrix.MultiplyPoint3x4(EdgeGraphUtility.GetNode(footprint.edges[i].Node1, ref footprint.nodes).Position); Vector3 n2PosWorld = footprintTRSMatrix.MultiplyPoint3x4(EdgeGraphUtility.GetNode(footprint.edges[i].Node2, ref footprint.nodes).Position); Vector3 n1PosGraph = graph.transform.InverseTransformPoint(n1PosWorld); Vector3 n2PosGraph = graph.transform.InverseTransformPoint(n2PosWorld); if (!EdgeGraphUtility.PointIsInside(n1PosGraph, graph.mainPrimitives[0].nodes, graph.mainPrimitives[0].edges) || !EdgeGraphUtility.PointIsInside(n2PosGraph, graph.mainPrimitives[0].nodes, graph.mainPrimitives[0].edges)) { return(false); } } return(true); }
void OnSceneGUI() { if (placer.handPlacementEnabled && placer.footprintPrefabsOnEdge.Count > 0) { controls.Update(); Vector3 newFootprintPos = Vector3.zero; Quaternion newFootprintRot = Quaternion.identity; bool placeInside = EdgeGraphUtility.PointIsInside(controls.cursorLocalPosition, placer.graph.mainPrimitives[0].nodes, placer.graph.mainPrimitives[0].edges); if (controls.controlIsPressed) { if (placer.handPlacementOnEdge) { if (handPlacedIndex >= placer.footprintPrefabsOnEdge.Count) { handPlacedIndex = placer.footprintPrefabsOnEdge.Count - 1; } } else { if (handPlacedIndex >= placer.footprintPrefabsInside.Count) { handPlacedIndex = placer.footprintPrefabsInside.Count - 1; } } if (Event.current.isKey && Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.W) { if (placer.handPlacementOnEdge) { handPlacedIndex = UtilityTools.Helper.GetNextIndex <GameObject>(placer.footprintPrefabsOnEdge, handPlacedIndex); } else { handPlacedIndex = UtilityTools.Helper.GetNextIndex <GameObject>(placer.footprintPrefabsInside, handPlacedIndex); } } else if (Event.current.isKey && Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Q) { if (placer.handPlacementOnEdge) { handPlacedIndex = UtilityTools.Helper.GetPrevIndex <GameObject>(placer.footprintPrefabsOnEdge, handPlacedIndex); } else { handPlacedIndex = UtilityTools.Helper.GetPrevIndex <GameObject>(placer.footprintPrefabsInside, handPlacedIndex); } } else if (Event.current.isKey && Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.E) { placer.handPlacementOnEdge = !placer.handPlacementOnEdge; } Quaternion rot; Vector3 closestPoint; placer.GetFootprintPosAndRotAtTarget(controls.cursorWorldPosition, out newFootprintPos, out rot, out closestPoint, handPlacedIndex, placer.handPlacementOnEdge, placeInside); if (placer.handPlacementOnEdge) { newFootprintRot = rot; } Footprint fp; if (placer.handPlacementOnEdge) { fp = UtilityTools.Helper.GetComponentInPrefabChildren <Footprint>(placer.footprintPrefabsOnEdge[handPlacedIndex]); } else { fp = UtilityTools.Helper.GetComponentInPrefabChildren <Footprint>(placer.footprintPrefabsInside[handPlacedIndex]); } if (fp != null) { Handles.color = Color.yellow; Matrix4x4 newPosMatrix = Matrix4x4.TRS(newFootprintPos, newFootprintRot, Vector3.one); for (int i = 0; i < fp.nodes.Count; i++) { Node cur = fp.nodes[i]; Node next; if (i == fp.nodes.Count - 1) { next = fp.nodes[0]; } else { next = fp.nodes[i + 1]; } Handles.DrawLine(newPosMatrix.MultiplyPoint3x4(cur.Position), newPosMatrix.MultiplyPoint3x4(next.Position)); Handles.CubeCap(0, newPosMatrix.MultiplyPoint3x4(cur.Position), Quaternion.LookRotation(newPosMatrix.GetColumn(2), newPosMatrix.GetColumn(1)), .2f); if (placer.handPlacementOnEdge) { Handles.Label(controls.cursorWorldPosition, placer.footprintPrefabsOnEdge[handPlacedIndex].name, "box"); } else { Handles.Label(controls.cursorWorldPosition, placer.footprintPrefabsInside[handPlacedIndex].name, "box"); } Handles.SphereCap(0, newFootprintPos, Quaternion.identity, .2f); Handles.SphereCap(0, closestPoint, Quaternion.identity, .2f); } } } if (controls.MouseClickedDown()) { if (controls.controlIsPressed) { placer.PlaceFootprint(newFootprintPos, newFootprintRot, handPlacedIndex, placer.handPlacementOnEdge, true); if (!placer.handPlacementOnEdge) { newFootprintRot = Quaternion.AngleAxis(UnityEngine.Random.Range(0f, 360f), Vector3.up); } } } } Handles.BeginGUI(); GUILayout.Window(1, new Rect(16f, 232f, 150f, 50f), DrawSceneWindow, "Placement by hand"); Handles.EndGUI(); }
bool FootprintOverlapsOthers(Footprint footprint, Matrix4x4 footprintTRSMatrix) { // Check if any footprint edges cross each other for (int i = 0; i < footprint.edges.Count; i++) { Vector3 n1Pos = footprintTRSMatrix.MultiplyPoint3x4(EdgeGraphUtility.GetNode(footprint.edges[i].Node1, ref footprint.nodes).Position); Vector3 n2Pos = footprintTRSMatrix.MultiplyPoint3x4(EdgeGraphUtility.GetNode(footprint.edges[i].Node2, ref footprint.nodes).Position); for (int j = 0; j < instantiatedFootprints.Count; j++) { List <Node> placedFootprintWorldNodes = new List <Node>(); instantiatedFootprints[j].nodes.ForEach((node) => { Node newNode = new Node(node); newNode.Position = instantiatedFootprints[j].transform.TransformPoint(node.Position); placedFootprintWorldNodes.Add(newNode); }); for (int k = 0; k < instantiatedFootprints[j].edges.Count; k++) { Vector3 n3Pos = instantiatedFootprints[j].transform.TransformPoint(EdgeGraphUtility.GetNode(instantiatedFootprints[j].edges[k].Node1, ref instantiatedFootprints[j].nodes).Position); Vector3 n4Pos = instantiatedFootprints[j].transform.TransformPoint(EdgeGraphUtility.GetNode(instantiatedFootprints[j].edges[k].Node2, ref instantiatedFootprints[j].nodes).Position); Vector3 intersect; if (UtilityTools.MathHelper.AreIntersecting(out intersect, n1Pos, n2Pos, n3Pos, n4Pos) == 1) { return(true); } } } } // Check if footprint is inside placed footprint Vector3 nodePosWorld; for (int i = 0; i < footprint.nodes.Count; i++) { nodePosWorld = footprintTRSMatrix.MultiplyPoint3x4(footprint.nodes[i].Position); for (int j = 0; j < instantiatedFootprints.Count; j++) { List <Node> placedFootprintWorldNodes = new List <Node>(); instantiatedFootprints[j].nodes.ForEach((node) => { Node newNode = new Node(node); newNode.Position = instantiatedFootprints[j].transform.TransformPoint(node.Position); placedFootprintWorldNodes.Add(newNode); }); if (EdgeGraphUtility.PointIsInside(nodePosWorld, placedFootprintWorldNodes, instantiatedFootprints[j].edges)) { return(true); } } } // Check if any placed footprint is inside the footprint List <Node> footprintWorldNodes = new List <Node>(); footprint.nodes.ForEach((node) => { Node newNode = new Node(node); newNode.Position = footprintTRSMatrix.MultiplyPoint3x4(node.Position); footprintWorldNodes.Add(newNode); }); for (int i = 0; i < instantiatedFootprints.Count; i++) { List <Node> placedFootprintWorldNodes = new List <Node>(); instantiatedFootprints[i].nodes.ForEach((node) => { Node newNode = new Node(node); newNode.Position = instantiatedFootprints[i].transform.TransformPoint(node.Position); placedFootprintWorldNodes.Add(newNode); }); for (int j = 0; j < placedFootprintWorldNodes.Count; j++) { if (EdgeGraphUtility.PointIsInside(placedFootprintWorldNodes[j].Position, footprintWorldNodes, footprint.edges)) { return(true); } } } return(false); }
public void FillWithEdgesWithFootprints() { ClearUnmodifiedFootprints(true); //List<Footprint> instantiatedFootprints = new List<Footprint>(); Vector3 target; Vector3 bPos; Vector3 closestPoint; Quaternion bRot; Matrix4x4 footprintTRSMatrix; Footprint footprint; Primitive primitive = graph.mainPrimitives[0]; List <Node> nodes = primitive.nodes; List <Edge> edges = primitive.edges; // Two passes are made, first one places random footprints, the second tries every footprint on every position so smaller gaps left are filled for (int pass = 1; pass <= 2; pass++) { for (int i = 0; i < edges.Count; i++) { Node n1 = EdgeGraphUtility.GetNode(edges[i].Node1, ref nodes); Node n2 = EdgeGraphUtility.GetNode(edges[i].Node2, ref nodes); Vector3 n1Pos = transform.TransformPoint(n1.Position); Vector3 n2Pos = transform.TransformPoint(n2.Position); //Vector3 n1n2 = (n2Pos - n1Pos); int footprintIdx = GetRandomEdgeFootPrintIdx(); for (float t = 0f; t < 1f; t += .005f) { target = Vector3.Lerp(n1Pos, n2Pos, t); GetFootprintPosAndRotAtTarget(target, out bPos, out bRot, out closestPoint, footprintIdx); if (pass == 1) { footprint = UtilityTools.Helper.GetComponentInPrefabChildren <Footprint>(footprintPrefabsOnEdge[footprintIdx]); footprintTRSMatrix = Matrix4x4.TRS(bPos, bRot, Vector3.one); if (!FootprintOverlapsOthers(footprint, footprintTRSMatrix) && FootprintIsInsideGraph(footprint, footprintTRSMatrix)) { PlaceFootprint(bPos, bRot, footprintIdx, true); footprintIdx = GetRandomEdgeFootPrintIdx(); } } else { for (int j = 0; j < footprintPrefabsOnEdge.Count; j++) { footprint = UtilityTools.Helper.GetComponentInPrefabChildren <Footprint>(footprintPrefabsOnEdge[j]); footprintTRSMatrix = Matrix4x4.TRS(bPos, bRot, Vector3.one); if (!FootprintOverlapsOthers(footprint, footprintTRSMatrix) && FootprintIsInsideGraph(footprint, footprintTRSMatrix)) { PlaceFootprint(bPos, bRot, j, true); } } } } } } }