/// <summary> /// Creates a new instance of <see cref="LineExtrusionResults"/> with values for its public fields. /// </summary> /// <param name="originalLinePointList">The original line points</param> /// <param name="contours">List of connected contours resulting from line extrusion.</param> /// <param name="removedContours">List of contours removed from initially-extruded surface because they were too close to the original line.</param> /// <param name="contourChunkCollections">List of connected contours resulting from line extrusion, as <see cref="ChunkBetweenIntersectionsCollection"/>.</param> /// <param name="removedContourChunkCollections">List of contours removed from initially-extruded surface because they were too close to the original line, as <see cref="ChunkBetweenIntersectionsCollection"/>.</param> /// <param name="intersectionPoints">The intersection points of extruded segments.</param> /// <param name="initiallyExtrudedPoints">Set of initially-extruded points, before contours removed for being too close to the original line.</param> /// <param name="lineExtrusionConfiguration">Line extrusion configuration.</param> public LineExtrusionResults(SegmentwiseLinePointListUV originalLinePointList, List <Vector2WithUV[]> contours, List <Vector2WithUV[]> removedContours, List <ChunkBetweenIntersectionsCollection> contourChunkCollections, List <ChunkBetweenIntersectionsCollection> removedContourChunkCollections, List <IntersectionPoint> intersectionPoints, SegmentwiseExtrudedPointListUV initiallyExtrudedPoints, LineExtrusionConfiguration lineExtrusionConfiguration) { OriginalLinePointList = originalLinePointList; Contours = contours; ContoursWithAlteredUParameters = GetContoursWithAlteredUParameters(contours, lineExtrusionConfiguration); RemovedContours = removedContours; ContourChunkCollections = contourChunkCollections; RemovedContourChunkCollections = removedContourChunkCollections; IntersectionPoints = intersectionPoints; InitiallyExtrudedPoints = initiallyExtrudedPoints; ConnectedSegmentsExtrusionResults = new ConnectedSegmentsExtrusionResults(ContoursWithAlteredUParameters); }
/// <summary> /// Extract a list of <see cref="Vector2WithUV[]"/> representing contiguous lines of extruded points. /// </summary> /// <param name="linePoints">The line from which extruded points came from.</param> /// <param name="extrudedPoints">The extruded points.</param> /// <param name="lineExtrusionConfiguration">The extrusion configuration.</param> private static LineExtrusionResults GetExtrudedLines(IList <LinePointUV> linePoints, IList <ExtrudedPointUV> extrudedPoints, LineExtrusionConfiguration lineExtrusionConfiguration) { SegmentwiseLinePointListUV linePointList = new SegmentwiseLinePointListUV(linePoints); SegmentwiseExtrudedPointListUV extrudedPointList = new SegmentwiseExtrudedPointListUV(extrudedPoints); //Note that the extruded maximum segment distance can be large (order of extrusion distance) when the original line has a kink (discontinuous derivative) List <IntersectionPoint> intersectionPoints; List <IntersectionPointPair> chunkIntersectionEndpoints; SegmentedIntersectionDetermination.FindIntersectionPointsAndChunkEndpoints(extrudedPointList, out intersectionPoints, out chunkIntersectionEndpoints); return(ExtractLineExtrusionResults_FindContinuousLast(linePointList, extrudedPointList, lineExtrusionConfiguration, intersectionPoints, chunkIntersectionEndpoints)); }
/// <summary> /// Converts a <see cref="SegmentwiseLinePointListUV"/> of original line points converts it into an array of <see cref="Vector4"/>, with the local point and uv packed into four components. /// </summary> /// <param name="originalLinePointList">The list oriignal line points and UVs.</param> protected Vector4[] ConvertOriginalLineToLocalVector4Array(SegmentwiseLinePointListUV originalLinePointList) { var points = originalLinePointList.Points; int numPoints = points.Count; int numPointsToAdd = Mathf.Min(numPoints, _maxOriginalLineArrayLength); Vector4[] array = new Vector4[_maxOriginalLineArrayLength]; for (int i = 0; i < numPointsToAdd; i++) { array[i] = LinePointUVToLocalVector4(points[i]); } return(array); }
/// <summary> /// Updates the extrusion with the given <see cref="_discretization"/> and <see cref="Extrusion"/> values. /// Updates the <see cref="MeshFilter"/> component with the resulting Mesh. /// </summary> public void UpdateExtrusion() { if (_meshFilter == null) { _meshFilter = GetComponent <MeshFilter>(); } if (_meshRenderer == null) { _meshRenderer = GetComponent <MeshRenderer>(); } bool doExtrusion = Math.Abs(_extrusion) > ExtrusionNumericalPrecision.MinimumExtrusionDistanceExclusive; if (doExtrusion) { try { _lineExtrusionConfiguration = GetLineExtrusionConfiguration(_extrusion); _extrusionResults = SegmentedLineExtrusionFromIntersection.ExtrudeSegmentedLineBothDirections(this, _lineExtrusionConfiguration); var linePointsWithUVs = LineSegmentation.GetLinePointsUV(this); var segmentwiseLinePointList = new SegmentwiseLinePointListUV(linePointsWithUVs); _extrudedMesh = ExtrusionTriangulator2D.TriangulatePolygon(_extrusionResults, segmentwiseLinePointList, _lineExtrusionConfiguration); var verts = _extrudedMesh.vertices; for (int i = 0; i < verts.Length; i++) { verts[i] = transform.InverseTransformPoint(verts[i]); } _extrudedMesh.vertices = verts; _meshFilter.mesh = _extrudedMesh; bool singleContour = _extrusionResults.Contours.Count <= 1; _meshRenderer.material = singleContour ? _singleContourMaterial : _multipleContourMaterial; (singleContour ? OnSingleContourExtrusionUpdated : OnMultipleContourExtrusionUpdated).Invoke(); } catch (Exception e) { Debug.LogWarning(string.Format("Error in extrusion of amount {0}: {1}\n{2}.", _extrusion, e.Message, e.StackTrace)); _extrudedMesh = new Mesh(); _meshFilter.mesh = _extrudedMesh; } finally { } } else { _extrudedMesh = new Mesh(); _meshFilter.mesh = _extrudedMesh; } }
/// <summary> /// Triangulate a line based on a single closed contour of extruded points by connecting points of equal u-parameter. /// </summary> /// <param name="originalLinePointList">Original line points</param> /// <param name="lineExtrusionResults">Line extrusion results</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> public Mesh TriangulateClosedContour(LineExtrusionResults lineExtrusionResults, SegmentwiseLinePointListUV originalLinePointList, LineExtrusionConfiguration extrusionConfiguration) { return(TriangulateLine_ConnectExtrudedPointsOfSameUParameter(lineExtrusionResults, extrusionConfiguration)); }
/// <summary> /// Extract <see cref="LineExtrusionResults"/> containing contiguous chunks of extruded points, after first determining intersection points and removing chunks too close to the original <paramref name="linePoints"/>. /// </summary> /// <param name="linePoints">The line against which chunks are compared by distance.</param> /// <param name="initiallyExtrudedPointList">The initially extruded points list.</param> /// <param name="lineExtrusionConfiguration">The extrusion configuration.</param> /// <param name="intersectionPoints">All intersection points between extruded segments.</param> /// <param name="chunkIntersectionEndpoints">Pairs of neighbouring intersection points, acting as chunk endpoints.</param> private static LineExtrusionResults ExtractLineExtrusionResults_FindContinuousLast(SegmentwiseLinePointListUV linePoints, SegmentwiseExtrudedPointListUV initiallyExtrudedPointList, LineExtrusionConfiguration lineExtrusionConfiguration, List <IntersectionPoint> intersectionPoints, List <IntersectionPointPair> chunkIntersectionEndpoints) { var extrudedChunksBetweenIntersections = ExtractChunksBetweenIntersections(initiallyExtrudedPointList, chunkIntersectionEndpoints); var removedChunks = SegmentedExtrudedChunkRemoval.RemoveChunksThatAreTooClose(extrudedChunksBetweenIntersections, linePoints, lineExtrusionConfiguration.ExtrusionAmount, intersectionPoints); var chunkCollectionList = ConnectExtrudedChunksBetweenIntersections(extrudedChunksBetweenIntersections); var removedChunksConnected = ConnectExtrudedChunksBetweenIntersections(removedChunks); var chunkConnector = lineExtrusionConfiguration.GetExtrudedChunkContourConnector(); List <Vector2WithUV[]> contours = chunkConnector.ConnnectChunksBetweenIntersectionsIntoPointsLists(chunkCollectionList); List <Vector2WithUV[]> removedContours = chunkConnector.ConnnectChunksBetweenIntersectionsIntoPointsLists(removedChunksConnected); return(new LineExtrusionResults(linePoints, contours, removedContours, chunkCollectionList, removedChunksConnected, intersectionPoints, initiallyExtrudedPointList, lineExtrusionConfiguration)); }
/// <summary> /// Determine if a chunk of extruded points is too close to a line of points, determined by comparing the extruded point whose parameter is furthest from any intersection points. /// </summary> /// <param name="extrudedContinuousChunk">Chunk of extruded points between two intersection endpoints.</param> /// <param name="linePoints">Points on the line from which to determine distance.</param> /// <param name="intersectionPoints">All intersection points between extruded segments.</param> /// <param name="extrusionAmount">The extrusion amount.</param> private static bool IsExtractedContinuousChunkooClose_DeterminedFromFurthestParameter(ChunkBetweenIntersections extrudedContinuousChunk, SegmentwiseLinePointListUV linePoints, IList <IntersectionPoint> intersectionPoints, float extrusionAmount) { bool tooClose; if (extrudedContinuousChunk.ExtrudedPoints.Count > 0) { var pointToCheck = PointOfLargestParameterDifference(extrudedContinuousChunk.ExtrudedPoints, intersectionPoints); tooClose = SegmentedLineUtil.IsCloserThanExtrusionDistance_Segmentwise(pointToCheck, linePoints, extrusionAmount); } else { tooClose = IsIntersectionPointChunkSegmentCloserThanExtrusionDistance(extrudedContinuousChunk.StartIntersection, extrudedContinuousChunk.EndIntersection, linePoints, extrusionAmount); } return(tooClose); }
/// <summary> /// Remove chunks that are too close to a line, from a list of all extruded chunks between intersections. /// Returns the removed chunks. /// </summary> /// <param name="extrudedChunksBetweenIntersections">Extruded chunks between extruded line intersection points. Chunks too close are removed from this list.</param> /// <param name="linePoints">The line against which chunks are compared by distance.</param> /// <param name="extrusionAmount">The extrusion amount.</param> /// <param name="intersectionPoints">The intersection points.</param> /// <returns>The removed chunks.</returns> internal static List <ChunkBetweenIntersections> RemoveChunksThatAreTooClose(List <ChunkBetweenIntersections> extrudedChunksBetweenIntersections, SegmentwiseLinePointListUV linePoints, float extrusionAmount, List <IntersectionPoint> intersectionPoints) { List <ChunkBetweenIntersections> removed = new List <ChunkBetweenIntersections>(); for (int i = extrudedChunksBetweenIntersections.Count - 1; i >= 0; i--) { var thisChunk = extrudedChunksBetweenIntersections[i]; var extractedIsTooClose = IsExtractedContinuousChunkooClose_DeterminedFromFurthestParameter(thisChunk, linePoints, intersectionPoints, extrusionAmount); if (extractedIsTooClose) { removed.Add(thisChunk); extrudedChunksBetweenIntersections.RemoveAt(i); } } removed.Reverse(); return(removed); }
/// <summary> /// Determines if a chunk between intersection points that contains no other extruded points (ie. the chunk is a single line segment of beginning and ending with two intersection points) is closer than the extrusion distance to the original line. /// Calculates based on the original line segmentwise. /// </summary> /// <param name="intersectionSegmentStart">Intersection point comprising the start of the segment.</param> /// <param name="intersectionSegmentEnd">Intersection point comprising the end of the segment.</param> /// <param name="originalLinePointList">List of original line points</param> /// <param name="extrusionAmount">The extrusion amount.</param> private static bool IsIntersectionPointChunkSegmentCloserThanExtrusionDistance_OriginalLineSegmentwise(IntersectionPoint intersectionSegmentStart, IntersectionPoint intersectionSegmentEnd, SegmentwiseLinePointListUV originalLinePointList, float extrusionAmount) { var linePoints = originalLinePointList.Points; var linePointsMaximumDelta = originalLinePointList.MaxSegmentDistance; var numSegments = linePoints.Count - 1; var segmentIndex1 = Math.Max(0, Math.Min(numSegments - 1, intersectionSegmentStart.FirstPointSegmentIndex)); var segmentIndex2 = Math.Max(0, Math.Min(numSegments - 1, intersectionSegmentStart.FirstPointSegmentIndex2)); var segmentIndex3 = Math.Max(0, Math.Min(numSegments - 1, intersectionSegmentStart.SecondPointSegmentIndex)); var segmentIndex4 = Math.Max(0, Math.Min(numSegments - 1, intersectionSegmentStart.SecondPointSegmentIndex2)); var segmentIndex5 = Math.Max(0, Math.Min(numSegments - 1, intersectionSegmentEnd.FirstPointSegmentIndex)); var segmentIndex6 = Math.Max(0, Math.Min(numSegments - 1, intersectionSegmentEnd.FirstPointSegmentIndex2)); var segmentIndex7 = Math.Max(0, Math.Min(numSegments - 1, intersectionSegmentEnd.SecondPointSegmentIndex)); var segmentIndex8 = Math.Max(0, Math.Min(numSegments - 1, intersectionSegmentEnd.SecondPointSegmentIndex2)); var distanceExtruded1 = LineSegmentUtil.DistanceToSegment(linePoints[segmentIndex1].Point, linePoints[segmentIndex1 + 1].Point, intersectionSegmentStart.Point); var distanceExtruded2 = LineSegmentUtil.DistanceToSegment(linePoints[segmentIndex2].Point, linePoints[segmentIndex2 + 1].Point, intersectionSegmentStart.Point); var distanceExtruded3 = LineSegmentUtil.DistanceToSegment(linePoints[segmentIndex3].Point, linePoints[segmentIndex3 + 1].Point, intersectionSegmentStart.Point); var distanceExtruded4 = LineSegmentUtil.DistanceToSegment(linePoints[segmentIndex4].Point, linePoints[segmentIndex4 + 1].Point, intersectionSegmentStart.Point); var distanceExtruded5 = LineSegmentUtil.DistanceToSegment(linePoints[segmentIndex5].Point, linePoints[segmentIndex5 + 1].Point, intersectionSegmentEnd.Point); var distanceExtruded6 = LineSegmentUtil.DistanceToSegment(linePoints[segmentIndex6].Point, linePoints[segmentIndex6 + 1].Point, intersectionSegmentEnd.Point); var distanceExtruded7 = LineSegmentUtil.DistanceToSegment(linePoints[segmentIndex7].Point, linePoints[segmentIndex7 + 1].Point, intersectionSegmentEnd.Point); var distanceExtruded8 = LineSegmentUtil.DistanceToSegment(linePoints[segmentIndex8].Point, linePoints[segmentIndex8 + 1].Point, intersectionSegmentEnd.Point); bool isCloser = false; var extrusionAmountAbs = Mathf.Abs(extrusionAmount); int numSteps = 1;//We'll look every numSteps points to see what's closest, moving more steps when possible. for (int i = 0; i < numSegments; i += numSteps) { var distanceBetweenSegments = LineSegmentUtil.DistanceBetweenSegments(intersectionSegmentStart.Point, intersectionSegmentEnd.Point, linePoints[i].Point, linePoints[i + 1].Point); bool useDefaultExtrusionAmount = true; var comparisonDistance = float.PositiveInfinity; if (i == segmentIndex1) { comparisonDistance = Math.Min(comparisonDistance, distanceExtruded1); useDefaultExtrusionAmount = false; } if (i == segmentIndex2) { comparisonDistance = Math.Min(comparisonDistance, distanceExtruded2); useDefaultExtrusionAmount = false; } if (i == segmentIndex3) { comparisonDistance = Math.Min(comparisonDistance, distanceExtruded3); useDefaultExtrusionAmount = false; } if (i == segmentIndex4) { comparisonDistance = Math.Min(comparisonDistance, distanceExtruded4); useDefaultExtrusionAmount = false; } if (i == segmentIndex5) { comparisonDistance = Math.Min(comparisonDistance, distanceExtruded5); useDefaultExtrusionAmount = false; } if (i == segmentIndex6) { comparisonDistance = Math.Min(comparisonDistance, distanceExtruded6); useDefaultExtrusionAmount = false; } if (i == segmentIndex7) { comparisonDistance = Math.Min(comparisonDistance, distanceExtruded7); useDefaultExtrusionAmount = false; } if (i == segmentIndex8) { comparisonDistance = Math.Min(comparisonDistance, distanceExtruded8); useDefaultExtrusionAmount = false; } if (useDefaultExtrusionAmount) { comparisonDistance = extrusionAmountAbs; } isCloser = distanceBetweenSegments < comparisonDistance; if (!useDefaultExtrusionAmount) { if ((i == segmentIndex1 || i == segmentIndex2) && segmentIndex1 == segmentIndex3 && segmentIndex2 == segmentIndex4 || (i == segmentIndex5 || i == segmentIndex6) && segmentIndex5 == segmentIndex7 && segmentIndex6 == segmentIndex8) { isCloser = false; } } if (isCloser) { break; } else { var distanceDiff = distanceBetweenSegments - extrusionAmountAbs; numSteps = Mathf.FloorToInt(Mathf.Max(1f, distanceDiff / linePointsMaximumDelta)); } } return(isCloser); }
/// <summary> /// Determines if a chunk between intersection points that contains no other extruded points (ie. the chunk is a single line segment of beginning and ending with two intersection points) is closer than the extrusion distance to the original line. /// </summary> /// <param name="intersectionSegmentStart">Intersection point comprising the start of the segment.</param> /// <param name="intersectionSegmentEnd">Intersection point comprising the end of the segment.</param> /// <param name="originalLinePointList">List of original line points</param> /// <param name="extrusionAmount">The extrusion amount.</param> private static bool IsIntersectionPointChunkSegmentCloserThanExtrusionDistance(IntersectionPoint point, IntersectionPoint extrudedOther, SegmentwiseLinePointListUV originalLinePointList, float extrusionAmount) { return(IsIntersectionPointChunkSegmentCloserThanExtrusionDistance_OriginalLineSegmentwise(point, extrudedOther, originalLinePointList, extrusionAmount)); }
/// <summary> /// Generates UV values for triangulated points on the interior of an extruded surface. /// </summary> /// <param name="triangulatedPoints">The triangulated points</param> /// <param name="lineExtrusionResults">Line extrusion resulting contours.</param> /// <param name="originalLinePointsList">Original line points</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> protected abstract Vector2[] GenerateTriangulatedPointUVs(Vector3[] triangulatedPoints, LineExtrusionResults lineExtrusionResults, SegmentwiseLinePointListUV originalLinePointsList, LineExtrusionConfiguration extrusionConfiguration);
/// <summary> /// Triangulate a polygon based on an outer closed contour of extruded points, further inner hole contours of extruded points, and the original line points from which they were extruded. /// </summary> /// <param name="originalLinePointList">Original line points</param> /// <param name="lineExtrusionResults">Line extrusion results</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> public Mesh TriangulatePolygonWithHoleContours(LineExtrusionResults lineExtrusionResults, SegmentwiseLinePointListUV originalLinePointList, LineExtrusionConfiguration extrusionConfiguration) { var polygon = new Polygon(); var outerThenAllInnerPointsList = lineExtrusionResults.Contours; var originalLinePoints = originalLinePointList.Points; int marker = 0; AddContourToPolygon(polygon, outerThenAllInnerPointsList[0], ref marker, contourIsHole: false); if (IncludeOriginalLinePoints) { AddOriginalLinePointsVerticesAndSegmentsToPolygon(originalLinePoints, polygon, ref marker); } if (IncludeRemovedContours) { List <Vector2WithUV[]> removedContours = lineExtrusionResults.RemovedContours; for (int i = 0; i < removedContours.Count; i++) { AddContourToPolygon(polygon, removedContours[i], ref marker, contourIsHole: false); } } for (int i = 1; i < outerThenAllInnerPointsList.Count; i++) { AddContourToPolygon(polygon, outerThenAllInnerPointsList[i], ref marker, contourIsHole: true); } var options = ConstraintOptions; var quality = QualityOptions; var iMesh = polygon.Triangulate(options, quality); var unityMesh = new Mesh(); Vector3[] vectorArray; Dictionary <int, int> vertexIdToArrayIndexDictionary; GetVector3ArrayAndIndexIdDictionaryFromVertices(iMesh.Vertices, out vectorArray, out vertexIdToArrayIndexDictionary); var trindicesArray = GetTrindicesArrayFromTriangles(iMesh.Triangles, vertexIdToArrayIndexDictionary); Vector2[] uvArray = GenerateTriangulatedPointUVs(vectorArray, lineExtrusionResults, originalLinePointList, extrusionConfiguration); unityMesh.vertices = vectorArray; unityMesh.triangles = trindicesArray; unityMesh.uv = uvArray; return(unityMesh); }
/// <summary> /// Triangulate a polygon based on line extrusion results and original line points from which extrusion occured. /// </summary> /// <param name="lineExtrusionResults">Results of line extrusion.</param> /// <param name="originalLinePointList">Original line points</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> public static Mesh TriangulatePolygon(LineExtrusionResults lineExtrusionResults, SegmentwiseLinePointListUV originalLinePointList, LineExtrusionConfiguration extrusionConfiguration) { PolygonHelper.OrderContourByAreaDescending(lineExtrusionResults.Contours); PolygonHelper.OrderContourByAreaDescending(lineExtrusionResults.ContoursWithAlteredUParameters); var outerThenAllInnerPointsListWithAlteredUVs = lineExtrusionResults.ContoursWithAlteredUParameters; Mesh mesh; if (outerThenAllInnerPointsListWithAlteredUVs.Count == 1) { mesh = extrusionConfiguration.GetSingleContourTriangulation().TriangulateClosedContour(lineExtrusionResults, originalLinePointList, extrusionConfiguration); } else if (outerThenAllInnerPointsListWithAlteredUVs.Count >= 1) { mesh = extrusionConfiguration.GetMultipleContourTriangulation().TriangulatePolygonWithHoleContours(lineExtrusionResults, originalLinePointList, extrusionConfiguration); } else { mesh = new Mesh(); } return(mesh); }
/// <summary> /// Generates empty UV values for triangulated points on the interior of an extruded surface. /// </summary> /// <param name="triangulatedPoints">The triangulated points</param> /// <param name="lineExtrusionResults">Line extrusion resulting contours.</param> /// <param name="originalLinePointsList">Original line points</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> protected override Vector2[] GenerateTriangulatedPointUVs(Vector3[] triangulatedPoints, LineExtrusionResults lineExtrusionResults, SegmentwiseLinePointListUV originalLinePointsList, LineExtrusionConfiguration extrusionConfiguration) { return(new Vector2[triangulatedPoints.Length]); }