public void PointModified(List <VolumePoint> data) { HUtils.log(); int dataCount = data.Count; if (data.Count == 0) { return; } int pointCount = numberOfPoints; for (int d = 0; d < dataCount; d++) { VolumePoint point = data[d]; if (!point.moved) { continue; } for (int p = 0; p < pointCount; p++) { if (point.lastPosition == _points[p].position) { _points[p].position = point.position; _points[p].MarkUnmodified(); } } } if (isModified) { MarkModified(); } }
public void AddPoint(Vector2Int newPosition) { VolumePoint newPoint = new VolumePoint(newPosition); _points.Add(newPoint); CheckVolume(); MarkModified(); }
public void AddPoint(Vector2Int newPosition) { HUtils.log(); Debug.Log("Volume.cs AddPoint(Vector2Int newPosition) newPosition=(" + newPosition.x + "," + newPosition.y + ")"); VolumePoint newPoint = new VolumePoint(newPosition); _points.Add(newPoint); CheckVolume(); MarkModified(); }
public VolumePoint Clone() { VolumePoint output = new VolumePoint(_position); output._controlA = _controlA; output._controlB = _controlB; output._curveStyle = _curveStyle; output._render = _render; output._facade = _facade; return(output); }
private void CheckInternalPointMovement(VolumePoint modifiedPoint) { int pointCount = numberOfPoints; for (int p = 0; p < pointCount; p++) { VolumePoint point = _points[p]; if (modifiedPoint == point) { continue; } if (modifiedPoint.lastPosition == point.position) { point.position = modifiedPoint.position; _points[p].MarkUnmodified(); } } }
public static bool HasNullFacades(IBuilding building) { int planCount = building.numberOfPlans; for (int pl = 0; pl < planCount; pl++) { IVolume plan = building[pl]; int facadeCount = plan.numberOfPoints; for (int f = 0; f < facadeCount; f++) { VolumePoint facadeData = plan[f]; if (facadeData.facade == null) { return(true); } } } return(false); }
public static void RoofFacadeInspectorGUI(Volume volume, int index) { VolumePoint point = volume[index]; // GUIStyle facadeLabelStyle = new GUIStyle(); // facadeLabelStyle.normal.background = new Texture2D(); EditorGUILayout.LabelField(string.Format("Facade: {0}", index + 1)); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Is Gabled", GUILayout.Width(60)); point.isGabled = EditorGUILayout.Toggle(point.isGabled, GUILayout.Width(20)); EditorGUILayout.EndHorizontal(); EditorGUI.BeginDisabledGroup(!point.isGabled); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Thickness"); point.gableThickness = EditorGUILayout.Slider(point.gableThickness, 0.1f, 5); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Additional Height"); point.gableHeight = EditorGUILayout.Slider(point.gableHeight, 0.1f, 5); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Simple Gable"); point.simpleGable = EditorGUILayout.Toggle(point.simpleGable); EditorGUILayout.EndHorizontal(); EditorGUI.BeginDisabledGroup(point.simpleGable); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Gable Design", GUILayout.Width(80)); point.gableStyle = (Gable)EditorGUILayout.ObjectField(point.gableStyle, typeof(Gable), false); EditorGUI.EndDisabledGroup(); EditorGUI.EndDisabledGroup(); EditorGUILayout.EndHorizontal(); // EditorGUILayout.BeginHorizontal(); // EditorGUILayout.LabelField("Thickness"); // _gable.thickness = EditorGUILayout.Slider(_gable.thickness, 0.1f, 5); // EditorGUILayout.EndHorizontal(); }
public bool Equals(VolumePoint p) { if (p == null) { return(false); } if (_position != p._position) { return(false); } if (_controlA != p._controlA) { return(false); } if (_controlB != p._controlB) { return(false); } if (_facade != p._facade) { return(false); } return(true); }
public void CalculateExternalWallAnchors() { HUtils.log(); if (_externalFacadeWallAnchors == null) { _externalFacadeWallAnchors = new Dictionary <int, List <Vector2Int> >(); } if (_externalWallAnchorsFacades == null) { _externalWallAnchorsFacades = new Dictionary <Vector2Int, List <int> >(); } if (_externalWallAnchors == null) { _externalWallAnchors = new List <Vector2Int>(); } _externalFacadeWallAnchors.Clear(); _externalWallAnchorsFacades.Clear(); _externalWallAnchors.Clear(); int pointCount = _points.Count; // int anchorCount = 0; for (int p = 0; p < pointCount; p++) { VolumePoint a = _points[p]; VolumePoint b = _points[(p + 1) % pointCount]; Vector2 av = a.position.vector2; Vector2 bv = b.position.vector2; _externalFacadeWallAnchors.Add(p, new List <Vector2Int>()); //new facade entry if (IsWallStraight(p)) { float length = Vector2.Distance(av, bv); int wallSections = Mathf.FloorToInt(length / _minimumWallUnitLength); if (wallSections < 1) { wallSections = 1; } for (int ws = 0; ws < wallSections + 1; ws++) { float lerp = ws / ((float)wallSections); Vector2Int point = new Vector2Int(Vector2.Lerp(av, bv, lerp)); _externalFacadeWallAnchors[p].Add(point); AddFacadeWallAnchors(point, p); if (ws < wallSections) { _externalWallAnchors.Add(point); } } } else { Vector2 cw0 = a.controlA.vector2; Vector2 cw1 = a.controlB.vector2; Vector2 last = Vector2.zero; float arcLength = 0; for (int t = 0; t < 10; t++) { Vector2 cp = FacadeSpline.Calculate(av, cw0, cw1, bv, t / 9f); if (t > 0) { arcLength += Vector2.Distance(cp, last); } last = cp; } int wallSections = Mathf.FloorToInt(arcLength / _minimumWallUnitLength); if (wallSections < 1) { wallSections = 1; } float sectionLength = arcLength / Mathf.Max(wallSections - 1f, 1f); int movement = wallSections * 10; int currentIndex = 0; Vector2 lastCP = av; Vector2 lastA = av; float lastDist = 0; Vector2Int avi = new Vector2Int(av); _externalFacadeWallAnchors[p].Add(avi); AddFacadeWallAnchors(avi, p); _externalWallAnchors.Add(avi); for (int m = 0; m < movement; m++) { float percent = m / (float)movement; Vector2 cp = FacadeSpline.Calculate(av, cw0, cw1, bv, percent); float dist = Vector2.Distance(lastA, cp); // Debug.Log(dist); if (dist >= sectionLength) { float cpDist = dist - lastDist; float overDist = dist - sectionLength; float targetPercent = 1 - Mathf.Clamp01(overDist / cpDist); Vector2 usePoint = Vector2.Lerp(lastCP, cp, targetPercent); lastA = usePoint; currentIndex++; Vector2Int upi = new Vector2Int(usePoint); _externalFacadeWallAnchors[p].Add(upi); AddFacadeWallAnchors(upi, p); _externalWallAnchors.Add(upi); if (currentIndex == wallSections - 2) { break; } } lastCP = cp; lastDist = dist; } Vector2Int bvi = new Vector2Int(bv); _externalFacadeWallAnchors[p].Add(bvi); AddFacadeWallAnchors(bvi, p); // _externalWallAnchors.Add(bvi); } } }
private static void ToMesh(ref BuildRMesh mesh, ref Shape shape, float roofBaseHeight, float meshHeight, int[] facadeIndices, IVolume volume, int submesh, Surface surface, bool generateDormers = false) { //TODO fix this error properly if (shape == null) { Debug.Log("ToMesh: Error to fix"); return; } List <Edge> edges = new List <Edge>(shape.edges); List <Edge> baseEdges = new List <Edge>(shape.baseEdges); float shapeHeight = shape.HeighestPoint(); float heightScale = meshHeight / shapeHeight; bool isFloor = meshHeight < 0.00001f; Dictionary <Node, int> shapeConnectionCount = new Dictionary <Node, int>(); Dictionary <Node, List <Node> > shapeConnections = new Dictionary <Node, List <Node> >(); int edgeCount = edges.Count; for (int e = 0; e < edgeCount; e++) { Edge edge = edges[e]; if (edge.length < Mathf.Epsilon) { continue; } if (!shapeConnectionCount.ContainsKey(edge.nodeA)) { shapeConnectionCount.Add(edge.nodeA, 0);//start at zero - we need two edges to make a shape... shapeConnections.Add(edge.nodeA, new List <Node> { edge.nodeB }); } else { shapeConnectionCount[edge.nodeA]++; if (!shapeConnections[edge.nodeA].Contains(edge.nodeB)) { shapeConnections[edge.nodeA].Add(edge.nodeB); } } if (!shapeConnectionCount.ContainsKey(edge.nodeB)) { shapeConnectionCount.Add(edge.nodeB, 0);//start at zero - we need two edges to make a shape... shapeConnections.Add(edge.nodeB, new List <Node> { edge.nodeA }); } else { shapeConnectionCount[edge.nodeB]++; if (!shapeConnections[edge.nodeB].Contains(edge.nodeA)) { shapeConnections[edge.nodeB].Add(edge.nodeA); } } } int baseEdgeCount = baseEdges.Count; List <Vector3[]> roofFaces = new List <Vector3[]>(); for (int b = 0; b < baseEdgeCount; b++) { int facadeIndex = facadeIndices[b]; bool isGabled = volume[facadeIndex].isGabled; if (!isGabled) { int facadeIndexLeft = (facadeIndex - 1 + volume.numberOfFacades) % volume.numberOfFacades; int facadeIndexRight = (facadeIndex + 1) % volume.numberOfFacades; bool isGabledLeft = volume[facadeIndexLeft].isGabled; bool isGabledRight = volume[facadeIndexRight].isGabled; Edge baseEdge = baseEdges[b]; Node nodeA = baseEdge.nodeA; Node nodeB = baseEdge.nodeB; Node currentNode = nodeA; Node lastNode = nodeB; int itMax = 50; List <Node> edgeShape = new List <Node>() { nodeA }; while (currentNode != nodeB) { List <Node> nodeConnections = shapeConnections[currentNode]; int nodeConnectionCount = nodeConnections.Count; float minAngle = Mathf.Infinity; Node nextNode = null; Vector2 currentDirection = (currentNode.position - lastNode.position).normalized; for (int n = 0; n < nodeConnectionCount; n++) { Node connectingNode = nodeConnections[n]; if (connectingNode == lastNode) { continue; //end this circus! } Vector2 nextDirection = (connectingNode.position - currentNode.position).normalized; float nodeAngle = SignAngleDirection(currentDirection, nextDirection); if (nodeAngle < minAngle) { minAngle = nodeAngle; nextNode = connectingNode; } } if (nextNode != null) { edgeShape.Add(nextNode); lastNode = currentNode; currentNode = nextNode; } itMax--; if (itMax < 0) { break; } } int edgeShapeCount = edgeShape.Count; if (edgeShapeCount == 4 && generateDormers) { Vector3[] edgeShapeV3 = new Vector3[4]; edgeShapeV3[0] = new Vector3(edgeShape[0].position.x, roofBaseHeight, edgeShape[0].position.y); edgeShapeV3[1] = new Vector3(edgeShape[3].position.x, roofBaseHeight, edgeShape[3].position.y); edgeShapeV3[2] = new Vector3(edgeShape[1].position.x, roofBaseHeight + meshHeight, edgeShape[1].position.y); edgeShapeV3[3] = new Vector3(edgeShape[2].position.x, roofBaseHeight + meshHeight, edgeShape[2].position.y); roofFaces.Add(edgeShapeV3); } if ((isGabledLeft || isGabledRight) && edgeShapeCount == 4)//modify shape if gables are detected { Vector3 p0 = edgeShape[0].position; Vector3 p1 = edgeShape[3].position; Vector3 p2 = edgeShape[1].position; Vector3 vector = p1 - p0; Vector3 dir = vector.normalized; Vector3 cross = Vector3.Cross(Vector3.back, dir); if (isGabledLeft) { float gableThickness = volume[facadeIndexLeft].gableThickness; bool simpleGable = volume[facadeIndexLeft].simpleGable; Gable gableStyle = volume[facadeIndexLeft].gableStyle; if (!simpleGable && gableStyle == null || !isFloor) { gableThickness = 0; } Vector3 newPointA = Vector3.Project(p2 - p1, cross) + dir * gableThickness; edgeShape[1].position = edgeShape[0].position + new Vector2(newPointA.x, newPointA.y); } if (isGabledRight) { float gableThickness = volume[facadeIndexRight].gableThickness; bool simpleGable = volume[facadeIndexRight].simpleGable; Gable gableStyle = volume[facadeIndexRight].gableStyle; if (!simpleGable && gableStyle == null || !isFloor) { gableThickness = 0; } Vector3 newPointB = Vector3.Project(p2 - p1, cross) - dir * gableThickness; edgeShape[2].position = edgeShape[3].position + new Vector2(newPointB.x, newPointB.y); } } Vector3[] verts = new Vector3[edgeShapeCount]; Vector2[] uvs = new Vector2[edgeShapeCount]; Vector3 baseShapeDirection = ToV3(nodeB.position - nodeA.position).normalized; float uvAngle = SignAngle(new Vector2(baseShapeDirection.x, baseShapeDirection.z).normalized) - 90; Vector2[] faceShape = new Vector2[edgeShapeCount]; Vector3[] normals = new Vector3[edgeShapeCount]; Vector4[] tangents = new Vector4[edgeShapeCount]; Vector4 tangent = BuildRMesh.CalculateTangent(baseShapeDirection); for (int i = 0; i < edgeShapeCount; i++) { Vector3 newVert = new Vector3(edgeShape[i].position.x, edgeShape[i].height * heightScale + roofBaseHeight, edgeShape[i].position.y); verts[i] = newVert; Vector2 baseUV = (i == 0) ? Vector2.zero : new Vector2(newVert.x - verts[0].x, newVert.z - verts[0].z); Vector2 newUV = Rotate(baseUV, uvAngle); float faceHeight = edgeShape[i].height * heightScale; newUV.y = Mathf.Sqrt((newUV.y * newUV.y) + (faceHeight * faceHeight)); if (surface != null) { newUV = surface.CalculateUV(newUV); } uvs[i] = newUV; faceShape[i] = edgeShape[i].position;//used for triangulation // normals[i] = normal; tangents[i] = tangent; } // int[] tris = EarClipper.Triangulate(faceShape, 0, -1); int[] tris = Poly2TriWrapper.Triangulate(faceShape, true); int triCount = tris.Length; if (triCount < 3) { continue; } Vector3 normal = BuildRMesh.CalculateNormal(verts[tris[0]], verts[tris[1]], verts[tris[2]]); for (int i = 0; i < edgeShapeCount; i++) { normals[i] = normal;//normCal[i].normalized; } mesh.AddData(verts, uvs, tris, normals, tangents, submesh); if (isGabled) { for (int t = 0; t < triCount; t += 3) { if (tris[t] == 0 || tris[t + 1] == 0 || tris[t + 2] == 0) { int beB = edgeShapeCount - 1; if (tris[t] == beB || tris[t + 1] == beB || tris[t + 2] == beB) { Vector3 b0 = verts[0]; Vector3 b1 = verts[beB]; int topIndex = 0; for (int tx = 0; tx < 3; tx++) { if (tris[t + tx] != 0 && tris[t + tx] != beB) { topIndex = tris[t + tx]; } } Vector3 b2 = verts[topIndex]; Vector3 baseV = b1 - b0; Vector3 dir = baseV.normalized; Vector3 face = Vector3.Cross(Vector3.up, dir); // float length = baseV.magnitude; Vector3 center = Vector3.Lerp(b0, b1, 0.5f); Vector3 up = Vector3.Project(b2 - b0, Vector3.up); Vector3 b3 = center + up; mesh.AddTri(b0, b2, b3, face, submesh); //left mesh.AddTri(b1, b3, b2, -face, submesh); //right mesh.AddTri(b0, b3, b1, dir, submesh); //face //clear triangle tris[t] = 0; tris[t + 1] = 0; tris[t + 2] = 0; } } } } } else if (isFloor) { Roof roof = volume.roof; Edge baseEdge = baseEdges[b]; Node nodeA = baseEdge.nodeA; Node nodeB = baseEdge.nodeB; Vector3 p0 = new Vector3(nodeA.position.x, heightScale + roofBaseHeight, nodeA.position.y); Vector3 p1 = new Vector3(nodeB.position.x, heightScale + roofBaseHeight, nodeB.position.y); Vector3 baseV = p1 - p0; Vector3 dir = baseV.normalized; Vector3 face = Vector3.Cross(Vector3.up, dir).normalized; Vector3 parapetEdgeModifier = dir * (roof.overhang - (roof.parapetFrontDepth + roof.parapetBackDepth)) * 1.05f; p0 += parapetEdgeModifier; p1 += -parapetEdgeModifier; // p0 += face * (roof.parapetFrontDepth + roof.parapetBackDepth + roof.overhang); VolumePoint volumePoint = volume[facadeIndices[b]]; bool simpleGable = volumePoint.simpleGable; Gable gableStyle = volume[facadeIndices[b]].gableStyle; if (!simpleGable && gableStyle == null) { simpleGable = true; } float thickness = volume[facadeIndices[b]].gableThickness; float additionalHeight = volume[facadeIndices[b]].gableHeight; float height = roof.height + additionalHeight; if (simpleGable) //generate a simple gable { int wallSubmesh = mesh.submeshLibrary.SubmeshAdd(roof.wallSurface); //surfaceMapping.IndexOf(roof.wallSurface); if (wallSubmesh == -1) { wallSubmesh = submesh; } Vector3 g0 = p0; Vector3 g1 = p0 + Vector3.up * additionalHeight; Vector3 g2 = g1 + dir * roof.floorDepth * 0.5f; Vector3 g3 = g2 + dir * roof.depth * 0.5f + Vector3.up * roof.height; Vector3 g7 = p1; Vector3 g6 = p1 + Vector3.up * additionalHeight; Vector3 g5 = g6 - dir * roof.floorDepth * 0.5f; Vector3 g4 = g5 - dir * roof.depth * 0.5f + Vector3.up * roof.height; Vector3 gF = -face * thickness; mesh.AddPlane(g0, g7, g1, g6, wallSubmesh); //bottom front mesh.AddPlane(g7 + gF, g0 + gF, g6 + gF, g1 + gF, wallSubmesh); //bottom back mesh.AddPlane(g1, g6, g1 + gF, g6 + gF, wallSubmesh); //bottom top mesh.AddPlane(g0, g1, g0 + gF, g1 + gF, wallSubmesh); //bottom sides mesh.AddPlane(g6, g7, g6 + gF, g7 + gF, wallSubmesh); mesh.AddPlane(g2, g5, g3, g4, wallSubmesh); //top front mesh.AddPlane(g5 + gF, g2 + gF, g4 + gF, g3 + gF, wallSubmesh); //top back mesh.AddPlane(g2 + gF, g2, g3 + gF, g3, wallSubmesh); //top sides mesh.AddPlane(g5, g5 + gF, g4, g4 + gF, wallSubmesh); //top sides mesh.AddPlane(g3 + gF, g3, g4 + gF, g4, wallSubmesh); //top top } else { Vector2 baseUV = new Vector2(0, volume.planHeight); GableGenerator.Generate(ref mesh, gableStyle, p0, p1, height, thickness, baseUV); } } } if (generateDormers) { DormerGenerator.Generate(ref mesh, volume, roofFaces); } }