// fusion de la forme de base (liner, margelle) et rectangle exterieur // pour la triangulation // voir http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf protected void MergedInnerAndOuter() { Bounds polyBounds = _polygon.bounds; Vector3 extents = polyBounds.extents; Vector3 center = polyBounds.center; // Pythagore float translation = _outlineOffset * 1.41421356f; // sqrt (2) Vector2 upRightDir = new Vector2 (1, 1).normalized * translation; Vector2 upRight = new Vector2 (center.x + extents.x, center.z + extents.z) + upRightDir; Vector2 downRightDir = new Vector2 (1, -1).normalized * translation; Vector2 downRight = new Vector2 (center.x + extents.x, center.z - extents.z) + downRightDir; Vector2 downLeftDir = new Vector2 (-1, -1).normalized * translation; Vector2 downLeft = new Vector2 (center.x - extents.x, center.z - extents.z) + downLeftDir; Vector2 upLeftDir = new Vector2 (-1, 1).normalized * translation; Vector2 upLeft = new Vector2 (center.x - extents.x, center.z + extents.z) + upLeftDir; PolygonRawData outerRawPoly = new PolygonRawData (); outerRawPoly.Add (upRight); outerRawPoly.Add (downRight); outerRawPoly.Add (downLeft); outerRawPoly.Add (upLeft); Polygon outerPolygon = new Polygon (outerRawPoly); _mergedPolygon = PolygonOperation.MergeInnerAndOuter (_polygon, outerPolygon); }
// fusionne deux polygones. Inner doit etre totalement inclus dans outer // permet la triangulation d'un polygonr avec un trou --> plage // voir http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf public static MergedPolygon MergeInnerAndOuter(Polygon inner, Polygon outer) { MergedPolygon mergedPolygon = new MergedPolygon (); PolygonRawData mergedPolyRaw = new PolygonRawData (); MutuallyVisibleVertices mvv = FindMutuallyVisibleVertices (inner, outer); LoopedList<Point2> innerPoints = inner.GetPoints (); LoopedList<Point2> outerPoints = outer.GetPoints (); int innerIndex = 0; for (; innerIndex <= mvv.innerIndex; ++innerIndex) { mergedPolyRaw.Add (innerPoints[innerIndex]); } mergedPolygon.originalIndex0 = mergedPolyRaw.Count - 1; mergedPolygon.originalIndex1 = mergedPolyRaw.Count; for (int counter = 0, outerIndex = mvv.outerIndex; counter < outerPoints.Count; ++counter, --outerIndex) { mergedPolyRaw.Add (outerPoints[outerIndex]); } mergedPolyRaw.Add (outerPoints[mvv.outerIndex] + mvv.duplicatedMVVOffset); mergedPolygon.duplicatedIndex1 = mergedPolyRaw.Count - 1; mergedPolyRaw.Add (innerPoints[mvv.innerIndex] + mvv.duplicatedMVVOffset); mergedPolygon.duplicatedIndex0 = mergedPolyRaw.Count - 1; for (; innerIndex < innerPoints.Count; ++innerIndex) { mergedPolyRaw.Add (innerPoints[innerIndex]); } mergedPolygon.polygonRawData = mergedPolyRaw; // Debug.Log (mergedPolygon.originalIndex0 + " " + mergedPolygon.originalIndex1 + " " + mergedPolygon.duplicatedIndex0 + " " + mergedPolygon.duplicatedIndex1); return mergedPolygon; }
// genere un ensemble de points correspondant au polygone avec ses avec arc de cercle public PolygonRawData GenerateWithCurveInverse() { PolygonRawData curvedPolygon = new PolygonRawData (); float minX = 0.0f; float maxX = 0.0f; float median=0.0f; foreach (Point2 point in _points) { if(point.GetX()>maxX) maxX=point.GetX(); if(point.GetX()<minX) minX=point.GetX(); } median = (maxX+minX)/2.0f; foreach (Point2 point in _points) //for (int i=_points.Count-1; i>=0; i--) { // Point2 point = _points[i]; float decalage = median - point.GetX(); float newX = median + decalage; point.Set( newX, point.GetY() ); /*point.Set( point.GetX(), point.GetY() );*/ if (point.GetJunction () == JunctionType.Broken) { curvedPolygon.Add (point); } else if (point.GetJunction () == JunctionType.Curved) { ArchedPoint2 ar = point as ArchedPoint2; foreach (Vector2 v in ar.GetCurve ()) { curvedPolygon.Add (v); } } } return curvedPolygon; }
// retourne l'arc de cercle sous forme d'une liste de point // voir ArcDrawer pour l'algo public PolygonRawData GetCurve() { PolygonRawData rawCurve = new PolygonRawData (); Vector2 firstPoint2Add = _prevTangentPoint; Vector2 lastPoint2Add = _nextTangentPoint; Vector2 startVector = (_prevTangentPoint - _center).normalized; Vector2 endVector = (_nextTangentPoint - _center).normalized; Vector2 angleMeasureReference = Vector2.right; if (_angleType == AngleType.Outside) { startVector = (_nextTangentPoint - _center).normalized; endVector = (_prevTangentPoint - _center).normalized; firstPoint2Add = _nextTangentPoint; lastPoint2Add = _prevTangentPoint; } float startAngle; if (Utils.Approximately (Vector3.Cross (startVector, angleMeasureReference).z, 0)) { startAngle = Vector2.Dot (startVector, angleMeasureReference) < 0 ? 180 : 0; } else { Quaternion startRotation = Quaternion.FromToRotation (angleMeasureReference, startVector); startAngle = startRotation.eulerAngles.z; } float endAngle; if (Utils.Approximately (Vector3.Cross (endVector, angleMeasureReference).z, 0)) { endAngle = Vector2.Dot (endVector, angleMeasureReference) < 0 ? 180 : 0; } else { Quaternion endRotation = Quaternion.FromToRotation (angleMeasureReference, endVector); endAngle = endRotation.eulerAngles.z; } // round angle startAngle = Mathf.Round(startAngle * 100) / 100; endAngle = Mathf.Round(endAngle * 100) / 100; //Debug.Log (startAngle + " " + endAngle); if (startAngle > endAngle) { endAngle += 360; } startAngle += ANGLE_STEP; float currentAngle = startAngle; rawCurve.Add (firstPoint2Add); while (currentAngle < endAngle) { float radAngle = currentAngle * Mathf.Deg2Rad; Vector2 arcPoint = new Vector2 (Mathf.Cos (radAngle), Mathf.Sin (radAngle)) * _measuredRadius + _center; if (_angleType == AngleType.Outside) { rawCurve.Insert (0, arcPoint); } else { rawCurve.Add (arcPoint); } currentAngle += ANGLE_STEP; } if (_angleType == AngleType.Outside) { rawCurve.Insert (0, lastPoint2Add); } else { rawCurve.Add (lastPoint2Add); } // if (_prevTangentPointMerged) // { // rawCurve.RemoveAt (0); // } // // if (_nextTangentPointMerged) // { // rawCurve.RemoveAt (rawCurve.Count - 1); // } return rawCurve; }
public void Generate(Polygon _polygon) { _rimParts.Clear (); _rimLofters.Clear (); _corners.Clear (); foreach (Transform child in _rim.transform) { GameObject.Destroy (child.gameObject); } _rars.Subdivide (_polygon); Polygon subdividedPolygon = new Polygon (_rars.GetSubdividedPolygon ()); subdividedPolygon.SetClosed (_polygon.IsClosed ()); //******************* OBTENTION DU PROFILE A EXTERNALISER ********************// PolygonRawData shapeRaw = new PolygonRawData (); /*shapeRaw.Add (new Vector2 (0, 0)); shapeRaw.Add (new Vector2 (0, 0.01f)); shapeRaw.Add (new Vector2 (-0.015f, 0.026f)); shapeRaw.Add (new Vector2 (-0.015f, 0.042f)); shapeRaw.Add (new Vector2 (-0.006f, 0.06f)); shapeRaw.Add (new Vector2 (0.01f, 0.069f)); shapeRaw.Add (new Vector2 (0.03f, 0.071f)); shapeRaw.Add (new Vector2 (0.049f, 0.066f)); shapeRaw.Add (new Vector2 (0.071f, 0.06f)); shapeRaw.Add (new Vector2 (0.1f, 0.052f)); shapeRaw.Add (new Vector2 (0.169f, 0.044f)); shapeRaw.Add (new Vector2 (0.249f, 0.041f)); shapeRaw.Add (new Vector2 (0.29f, 0.04f)); shapeRaw.Add (new Vector2 (0.298f, 0.038f)); shapeRaw.Add (new Vector2 (0.305f, 0.033f)); shapeRaw.Add (new Vector2 (0.309f, 0.024f)); shapeRaw.Add (new Vector2 (0.31f, 0.014f)); shapeRaw.Add (new Vector2 (0.31f, 0));*/ shapeRaw.Add (new Vector2 (-0.02f, 0.0f)); shapeRaw.Add (new Vector2 (0.28f, 0.0f)); shapeRaw.Add (new Vector2 (0.28f, 0.001f)); shapeRaw.Add (new Vector2 (-0.02f, 0.001f)); Polygon profile = new Polygon (shapeRaw); profile.SetClosed (false); //************************************************************************// Polygon currentPortion = null; bool inPortion = false; bool inCurve = false; int pointCounter = 0; int indexOffset = 0; // pour chaque point du polygon subdivisé // si c'est un angle prédéfini on charge le mesh margelle associé // sinon on crée un section avec l'outil loft jusqu'au prochain angle prédéfini foreach (Point2 currentPoint in subdividedPolygon.GetPoints ()) { float angle = currentPoint.GetAngle (); AngleType angleType = currentPoint.GetAngleType (); if (inPortion || inCurve) { Point2 pointToAdd = new Point2 (currentPoint); currentPortion.AddPoint (pointToAdd); } Edge2 nextEdge = currentPoint.GetNextEdge (); Edge2 prevEdge = currentPoint.GetPrevEdge (); Point2 nextPoint = null; Point2 prevPoint = null; if (nextEdge != null) { nextPoint = nextEdge.GetNextPoint2 (); prevPoint = prevEdge.GetPrevPoint2 (); float nextAngle = nextPoint.GetAngle (); AngleType nextAngleType = nextPoint.GetAngleType (); // stop case for onr portion if (Utils.Approximately (nextAngle, 90) && inPortion && nextAngleType == AngleType.Outside) { inPortion = false; currentPortion.SetClosed (false); GameObject portionGO = new GameObject ("portion"); portionGO.transform.parent = _rim.transform; portionGO.transform.localPosition = Vector3.zero; portionGO.transform.localRotation = Quaternion.identity; portionGO.transform.localScale = Vector3.one; portionGO.AddComponent<MeshRenderer> (); MeshFilter meshFilter = portionGO.AddComponent<MeshFilter> (); PolygonLofter polyLofter = new PolygonLofter (currentPortion, profile, meshFilter.mesh); polyLofter.SetCurveIndices (_rars.GetCurveIndices ()); polyLofter.SetIndexedAngleType (_rars.GetIndexedAngleType ()); polyLofter.SetIndexOffset (indexOffset + 1, subdividedPolygon.GetPoints ().Count); polyLofter.Generate (); portionGO.GetComponent<Renderer>().material = _portionMaterial; _rimParts.Add (currentPortion); _rimLofters.Add (polyLofter); } // angle prédéfini (90°) --> piece a charger if (Utils.Approximately (angle, 90) && angleType == AngleType.Outside) { _corners.Add (currentPoint); Vector3 angleRimPosition = new Vector3 (currentPoint.GetX (), 0, currentPoint.GetY ()); Vector2 nextEdgeDirection = currentPoint.GetNextEdge ().ToVector2 (); Vector3 toDirection = new Vector3 (nextEdgeDirection.x, 0, nextEdgeDirection.y); Quaternion angleRimOrientation = Quaternion.LookRotation (toDirection); GameObject rimCorner = Object.Instantiate (Resources.Load ("PoolDesigner/rimCorner")) as GameObject; rimCorner.transform.parent = _rim.transform; rimCorner.transform.localPosition = angleRimPosition; rimCorner.transform.localRotation = angleRimOrientation; rimCorner.transform.localScale = Vector3.one; //rimCorner.transform.GetChild (0).GetChild (1).renderer.material = _portionMaterial; rimCorner.transform.GetChild (0).GetChild (0).GetComponent<Renderer>().material = _portionMaterial; if (!inPortion) { inPortion = true; indexOffset = pointCounter; currentPortion = new Polygon (); } } /* if (Utils.Approximately (nextAngle, 90) && (currentPoint.GetX()==nextPoint.GetX()) && (currentPoint.GetY()==nextPoint.GetY()) && (currentPoint.GetX()==prevPoint.GetX()) && (currentPoint.GetY()==prevPoint.GetY())) { _corners.Add (currentPoint); Vector3 angleRimPosition = new Vector3 (currentPoint.GetX (), 0, currentPoint.GetY ()); Vector2 nextEdgeDirection = nextPoint.GetNextEdge ().ToVector2(); Vector3 toDirection = new Vector3 (nextEdgeDirection.x, 0, nextEdgeDirection.y); Quaternion angleRimOrientation = Quaternion.LookRotation (toDirection); GameObject rimCorner = Object.Instantiate (Resources.Load ("PoolDesigner/rimCorner")) as GameObject; rimCorner.transform.parent = _rim.transform; rimCorner.transform.localPosition = angleRimPosition; rimCorner.transform.localRotation = angleRimOrientation; rimCorner.transform.localScale = Vector3.one; //rimCorner.transform.GetChild (0).GetChild (1).renderer.material = _portionMaterial; rimCorner.transform.GetChild (0).GetChild (0).renderer.material = _portionMaterial; if (!inPortion) { inPortion = true; indexOffset = pointCounter; currentPortion = new Polygon (); } }*/ } ++pointCounter; } if (inPortion) // si on etait entrain d'ajouter des points a une portion { if (_polygon.IsClosed ()) // on ajoute les points restants { inPortion = false; Point2 currentPoint = subdividedPolygon.GetPoints ()[0]; float angle = currentPoint.GetAngle (); AngleType angleType = currentPoint.GetAngleType (); while (!Utils.Approximately (angle, 90) || angleType == AngleType.Inside) { Point2 pointToAdd = new Point2 (currentPoint); currentPortion.AddPoint (pointToAdd); currentPoint = currentPoint.GetNextEdge ().GetNextPoint2 (); angle = currentPoint.GetAngle (); angleType = currentPoint.GetAngleType (); } } GameObject portionGO = new GameObject ("portion"); portionGO.transform.parent = _rim.transform; portionGO.transform.localPosition = Vector3.zero; portionGO.transform.localRotation = Quaternion.identity; portionGO.transform.localScale = Vector3.one; portionGO.AddComponent<MeshRenderer> (); MeshFilter meshFilter = portionGO.AddComponent<MeshFilter> (); PolygonLofter polyLofter = new PolygonLofter (currentPortion, profile, meshFilter.mesh); polyLofter.SetIndexOffset (indexOffset + 1, subdividedPolygon.GetPoints ().Count); polyLofter.SetCurveIndices (_rars.GetCurveIndices ()); polyLofter.SetIndexedAngleType (_rars.GetIndexedAngleType ()); polyLofter.Generate (); portionGO.GetComponent<Renderer>().material = _portionMaterial; _rimParts.Add (currentPortion); _rimLofters.Add (polyLofter); } // Cas ou il n'y a pas de d'angle predefini // une seule portion qui correspond au polygone subdivise if (_corners.Count == 0) { GameObject portionGO = new GameObject ("portion"); portionGO.transform.parent = _rim.transform; portionGO.transform.localPosition = Vector3.zero; portionGO.transform.localRotation = Quaternion.identity; portionGO.transform.localScale = Vector3.one; portionGO.AddComponent<MeshRenderer> (); MeshFilter meshFilter = portionGO.AddComponent<MeshFilter> (); PolygonLofter polyLofter = new PolygonLofter (subdividedPolygon, profile, meshFilter.mesh); polyLofter.SetIndexOffset (0, subdividedPolygon.GetPoints ().Count); polyLofter.SetCurveIndices (_rars.GetCurveIndices ()); polyLofter.SetIndexedAngleType (_rars.GetIndexedAngleType ()); polyLofter.Generate (); portionGO.GetComponent<Renderer>().material = _portionMaterial; _rimParts.Add (_polygon); _rimLofters.Add (polyLofter); } _rimCount = 0; foreach (PolygonLofter lofter in _rimLofters) { _rimCount += lofter.GetRimCount (); } _rimCount += _corners.Count; }
public void Generate(Polygon _polygon) { //_polygon = new Polygon(_polygon.GenerateWithCurveInverse()); // On genere les meshs des composants de la piscine if (_polygon.GetPoints ().Count < 3) return; if (!_polygon.IsClosed ()) { _polygon.Close (); } _polygon = _polygon.GetMirrorX(); _polygon.UpdateBounds (); Vector2 translation = _polygon.GetPolygonCenter () * -1; Vector2 mirror = new Vector2(1,-1); // exprime le polygone en coordonnées monde, avec son repere centré sur son centre PolygonRawData polyRaw = new PolygonRawData (); foreach (Vector2 pt in _polygon.GenerateWithCurve ()) //foreach (Vector2 pt in _polygon.GenerateWithCurveInverse ()) //PolygonRawData polydata = _polygon.GenerateWithCurveInverse (); //polydata.Reverse(); //foreach (Vector2 pt in polydata) { Vector2 transformedPt = (pt + translation) * _polygonScaleFactor; /*Vector2 newpt = new Vector2(); newpt.x=pt.x; newpt.y=pt.y; newpt.y = 2*_polygon.bounds.center.z - newpt.y; Vector2 transformedPt = (newpt + translation) * _polygonScaleFactor;*/ polyRaw.Add (transformedPt); } _transformedPolygon = new Polygon (polyRaw); // generate liner Mesh linerMesh = _liner.GetComponent<MeshFilter> ().mesh; PolygonExtruder linerExtrusion = new PolygonExtruder (_transformedPolygon, linerMesh, -1.5f, false, true, true); linerExtrusion.Generate (); LinerScatteringMapper lsm = new LinerScatteringMapper (linerMesh); lsm.Generate (); PolygonExtruderMapper pem = new PolygonExtruderMapper (linerExtrusion); pem.Generate (); // generate sidewalk Mesh sidewalkMesh = _sidewalk.GetComponent<MeshFilter> ().mesh; SideWalkExtruder se = new SideWalkExtruder (_transformedPolygon, sidewalkMesh, -0.02f, 2); se.Generate (); PlannarMapper pm = new PlannarMapper (sidewalkMesh, Vector3.up); pm.Generate (); // generate rim _rimGenerator.Generate (_polygon); // generate occlusion PolygonRawData occluShape = new PolygonRawData (); occluShape.Add (new Vector2 (0.28f, 0)); occluShape.Add (new Vector2 (0.33f, 0)); Polygon occluProfile = new Polygon (occluShape); occluProfile.SetClosed (false); Mesh occluMesh = _occlusion.GetComponent<MeshFilter> ().mesh; PolygonLofter occluLofter = new PolygonLofter (_transformedPolygon, occluProfile, occluMesh); _occlusion.GetComponent<Renderer>().enabled = false; occluLofter.Generate (); // generate water Mesh waterMesh = _water.GetComponent<MeshFilter> ().mesh; PolygonExtruder waterPlan = new PolygonExtruder (_transformedPolygon, waterMesh, 0, true, false, false); waterPlan.Generate (); PlannarMapper waterMapper = new PlannarMapper (waterMesh, Vector3.down, UVChannel.uv0, 5); waterMapper.Generate (); // generate frieze Mesh friezeMesh = _frieze.GetComponent<MeshFilter> ().mesh; PolygonExtruder friezeExtrusion = new PolygonExtruder (_transformedPolygon, friezeMesh, -0.10f, false, false, true); friezeExtrusion.Generate (); PolygonExtruderMapper friezeMapper = new PolygonExtruderMapper (friezeExtrusion); friezeMapper.Generate (); LinerScatteringMapper lsmFrieze = new LinerScatteringMapper (friezeMesh); lsmFrieze.Generate (); // generate mask Mesh maskMesh = _mask.GetComponent<MeshFilter> ().mesh; PolygonExtruder maskExtrusion = new PolygonExtruder (_transformedPolygon, maskMesh, -0.10f, false, false, true); maskExtrusion.Generate (); PolygonExtruderMapper maskMapper = new PolygonExtruderMapper (maskExtrusion); maskMapper.Generate (); // generate collision mesh Mesh collisionMesh = new Mesh (); collisionMesh.name = "collision"; Polygon collisionPoly = PolygonOperation.GetOutlinedPolygon (_transformedPolygon, 0.33f); PolygonExtruder collisionExtruder = new PolygonExtruder(collisionPoly, collisionMesh, 0.07f, true, false, false); collisionExtruder.Generate (); _meshCollider.sharedMesh = collisionMesh; _meshCollider.convex = true; collisionMesh.RecalculateBounds (); // on ajoute le mesh de collision au renderer parent de la margelle // pour le calcul de la boundingBox lié a la fonction de redimensionnement // de la plage. _rim.gameObject.GetComponent<MeshFilter> ().mesh = collisionMesh; }