/// <summary> /// Sets up a cache with the given characteristics. /// </summary> /// <param name="rootPath">The absolute path to the root of the cache.</param> /// <param name="maxEntries">The maximum number of entries in the cache.</param> /// <param name="maxSizeBytes">The maximum combined size of all entries in the cache.</param> public void Setup(string rootPath, int maxEntries, long maxSizeBytes) { this.rootPath = rootPath; this.maxEntries = maxEntries; this.maxSizeBytes = maxSizeBytes; // Check that we have a reasonable config: PolyUtils.AssertNotNullOrEmpty(rootPath, "rootPath can't be null or empty"); PolyUtils.AssertTrue(Directory.Exists(rootPath), "rootPath must be an existing directory: " + rootPath); PolyUtils.AssertTrue(maxEntries >= 256, "maxEntries must be >= 256"); PolyUtils.AssertTrue(maxSizeBytes >= 1048576, "maxSizeBytes must be >= 1MB"); PtDebug.LogVerboseFormat("PBC initializing, root {0}, max entries {1}, max size {2}", rootPath, maxEntries, maxSizeBytes); md5 = MD5.Create(); InitializeCache(); setupDone = true; Thread backgroundThread = new Thread(BackgroundThreadMain); backgroundThread.IsBackground = true; backgroundThread.Start(); }
public static ConwayPoly ElongatedBicupola(int sides, bool gyro) { ConwayPoly poly = ElongatedCupola(sides); Face bottom = poly.Faces[sides * 2]; int i = 0; var middleVerts = bottom.GetVertices(); poly.Faces.Remove(bottom); poly.FaceRoles.RemoveAt(poly.FaceRoles.Count - 1); poly.FaceTags.RemoveAt(poly.FaceRoles.Count - 1); float baseOffset = -(_CalcSideLength(sides * 2) + _CalcCupolaHeight(sides)); float angleOffset = gyro ? 0.75f : 0.25f; ConwayPoly cap2 = _MakePolygon(sides, false, angleOffset, baseOffset, _CalcCupolaCapRadius(sides)); poly.Append(cap2); var edge2 = poly.Faces.Last().Halfedge.Prev; int edgeOffset = gyro ? 0 : 1; while (true) { var side1 = new List <Vertex> { middleVerts[PolyUtils.ActualMod(i * 2 - 1 - edgeOffset, sides * 2)], middleVerts[PolyUtils.ActualMod(i * 2 - edgeOffset, sides * 2)], edge2.Vertex }; poly.Faces.Add(side1); poly.FaceRoles.Add(ConwayPoly.Roles.New); poly.FaceTags.Add(new HashSet <Tuple <string, ConwayPoly.TagType> >()); var side2 = new List <Vertex> { middleVerts[PolyUtils.ActualMod(i * 2 - edgeOffset, sides * 2)], middleVerts[PolyUtils.ActualMod(i * 2 + 1 - edgeOffset, sides * 2)], edge2.Next.Vertex, edge2.Vertex, }; poly.Faces.Add(side2); poly.FaceRoles.Add(ConwayPoly.Roles.NewAlt); poly.FaceTags.Add(new HashSet <Tuple <string, ConwayPoly.TagType> >()); i++; edge2 = edge2.Next; if (i == sides) { break; } } poly.Halfedges.MatchPairs(); return(poly); }
public async Task Load(int segmentAttemptId) { SegmentAttempt = await Context.Services.GetSegmentAttempt(segmentAttemptId); MapViewModel = new MapControlViewModel( Context, SegmentAttempt.FormattedTime, PolyUtils.GetMapLocations(SegmentAttempt.Locations, SegmentAttempt.Jumps)); OnPropertyChanged(nameof(MapViewModel)); }
public async Task Load(int id) { Ride = await Context.Services.GetRide(id); MapViewModel = new MapControlViewModel( Context, Ride.DisplayName, PolyUtils.GetMapLocations(Ride.Locations, Ride.Jumps)); OnPropertyChanged(nameof(MapViewModel)); }
public async Task Load(int id) { Segment = await Context.Services.GetSegment(id); MapViewModel = new MapControlViewModel( Context, Segment.Name, PolyUtils.GetMapLocations(Segment.Locations), showRideFeatures: false); OnPropertyChanged(nameof(MapViewModel)); }
public static ConwayPoly GyroelongatedCupola(int sides) { ConwayPoly poly = Antiprism(sides * 2); Face topFace = poly.Faces[1]; ConwayPoly cap1 = _MakePolygon(sides, true, 0f, _CalcCupolaHeight(sides) + _CalcAntiprismHeight(sides * 2), _CalcCupolaCapRadius(sides)); poly.Append(cap1); int i = 0; var middleVerts = topFace.GetVertices(); poly.Faces.Remove(topFace); poly.FaceRoles.RemoveAt(1); poly.FaceTags.RemoveAt(1); var edge2 = poly.Faces.Last().Halfedge.Prev; while (true) { var side1 = new List <Vertex> { middleVerts[PolyUtils.ActualMod(i * 2 - 1, sides * 2)], middleVerts[PolyUtils.ActualMod(i * 2, sides * 2)], edge2.Vertex }; poly.Faces.Add(side1); poly.FaceRoles.Add(ConwayPoly.Roles.New); poly.FaceTags.Add(new HashSet <Tuple <string, ConwayPoly.TagType> >()); var side2 = new List <Vertex> { middleVerts[PolyUtils.ActualMod(i * 2, sides * 2)], middleVerts[PolyUtils.ActualMod(i * 2 + 1, sides * 2)], edge2.Next.Vertex, edge2.Vertex, }; poly.Faces.Add(side2); poly.FaceRoles.Add(ConwayPoly.Roles.NewAlt); poly.FaceTags.Add(new HashSet <Tuple <string, ConwayPoly.TagType> >()); i++; edge2 = edge2.Next; if (i == sides) { break; } } poly.Halfedges.MatchPairs(); return(poly); }
/// <summary> /// (Background thread). Main function that constantly checks the queues for pending requests and executes /// them as they arrive. /// </summary> private void BackgroundThreadMain() { try { while (true) { CacheRequest request; // Wait until the next request comes in. if (!requestsPendingWork.WaitAndDequeue(/* waitTime */ 5000, out request)) { continue; } // Process it. switch (request.type) { case RequestType.READ: BackgroundHandleReadRequest(request); break; case RequestType.WRITE: BackgroundHandleWriteRequest(request); break; case RequestType.CLEAR: BackgroundHandleClearRequest(request); break; default: PolyUtils.Throw("Invalid cache request type, should be READ, WRITE or CLEAR."); break; } } } //catch (ThreadAbortException) //{ // // That's ok (happens on project shutdown). //} catch (Exception ex) { Debug.LogErrorFormat("Cache background thread crashed: " + ex); } }
public CreateSegmentScreenViewModel(MainContext context, RideDto ride) : base(context) { segment = new SegmentDto(); Ride = ride; count = 1; displayText = "Tap on the map to set a start point"; MapViewModel = new MapControlViewModel( context, Ride?.DisplayName ?? "Map", ride != null ? PolyUtils.GetMapLocations(Ride.Locations, Ride.Jumps) : new List <MapLocation>(), isReadOnly: false, showRideFeatures: false, goToMapPageOnClick: false, mapType: MapType.Satellite, canChangeMapType: true); MapViewModel.MapTapped += MapViewModel_MapTapped; }
// dot(rayDir, rayDir) * t^2 + 2*t*dot(rayDir, rayOrig-center) + dot(rayOrig-center, rayOrig-center) - R*R=0 public bool Hit(Ray ray, float tMin, float tMax, ref HitRecord record) { float a = ray.Direction.LengthSquared; // dot(rayDir, rayDir) Vec3 temp = new Vec3(); Vec3.Subtract(ray.Origin, this.Center, temp); float b = 2 * ray.Direction.Dot(temp); //2*dot(rayDir, rayOrig-center) float c = temp.LengthSquared - this.Radius * this.Radius; //dot(rayOrig-center, rayOrig-center) - R*R if (!PolyUtils.HasRealRoot(a, b, c)) { // No hit return(false); } // Check first root for hit float firstRoot = PolyUtils.FirstRoot(a, b, c); if (firstRoot > tMin && firstRoot < tMax) { record.T = firstRoot; record.Point = ray.PointAt(firstRoot); Vec3.Subtract(record.Point, this.Center, temp); record.Normal = temp / this.Radius; record.Material = this.Material; return(true); } // Check second root for hit float secondRoot = PolyUtils.SecondRoot(a, b, c); if (secondRoot > tMin && secondRoot < tMax) { record.T = secondRoot; record.Point = ray.PointAt(secondRoot); Vec3.Subtract(record.Point, this.Center, temp); record.Normal = temp / this.Radius; record.Material = this.Material; return(true); } return(false); }
/// <summary> /// Co-routine that services one PendingRequest. This method must be called with StartCoroutine. /// </summary> /// <param name="request">The request to service.</param> private IEnumerator HandleWebRequest(PendingRequest request, BufferHolder bufferHolder) { // NOTE: This method runs on the main thread, but never blocks -- the blocking part of the work is // done by yielding the UnityWebRequest, which releases the main thread for other tasks while we // are waiting for the web request to complete (by the miracle of coroutines). // Let the caller create the UnityWebRequest, configuring it as they want. The caller can set the URL, // method, headers, anything they want. The only thing they can't do is call Send(), as we're in charge // of doing that. UnityWebRequest webRequest = request.creationCallback(); PtDebug.LogVerboseFormat("Web request: {0} {1}", webRequest.method, webRequest.url); bool cacheAllowed = cache != null && webRequest.method == "GET" && request.maxAgeMillis != CACHE_NONE; // Check the cache (if it's a GET request and cache is enabled). if (cacheAllowed) { bool cacheHit = false; byte[] cacheData = null; bool cacheReadDone = false; cache.RequestRead(webRequest.url, request.maxAgeMillis, (bool success, byte[] data) => { cacheHit = success; cacheData = data; cacheReadDone = true; }); while (!cacheReadDone) { yield return(null); } if (cacheHit) { PtDebug.LogVerboseFormat("Web request CACHE HIT: {0}, response: {1} bytes", webRequest.url, cacheData.Length); request.completionCallback(PolyStatus.Success(), /* responseCode */ 200, cacheData); // Return the buffer to the pool for reuse. CleanUpAfterWebRequest(bufferHolder); yield break; } else { PtDebug.LogVerboseFormat("Web request CACHE MISS: {0}.", webRequest.url); } } DownloadHandlerBuffer handler = new DownloadHandlerBuffer(); webRequest.downloadHandler = handler; // We need to asset that we actually succeeded in setting the download handler, because this can fail // if, for example, the creation callback mistakenly called Send(). PolyUtils.AssertTrue(webRequest.downloadHandler == handler, "Couldn't set download handler. It's either disposed of, or the creation callback mistakenly called Send()."); // Start the web request. This will suspend this coroutine until the request is done. PtDebug.LogVerboseFormat("Sending web request: {0}", webRequest.url); yield return(UnityCompat.SendWebRequest(webRequest)); // Request is finished. Call user-supplied callback. PtDebug.LogVerboseFormat("Web request finished: {0}, HTTP response code {1}, response: {2}", webRequest.url, webRequest.responseCode, webRequest.downloadHandler.text); PolyStatus status = UnityCompat.IsNetworkError(webRequest) ? PolyStatus.Error(webRequest.error) : PolyStatus.Success(); request.completionCallback(status, (int)webRequest.responseCode, webRequest.downloadHandler.data); // Cache the result, if applicable. if (!UnityCompat.IsNetworkError(webRequest) && cacheAllowed) { byte[] data = webRequest.downloadHandler.data; if (data != null && data.Length > 0) { byte[] copy = new byte[data.Length]; Buffer.BlockCopy(data, 0, copy, 0, data.Length); cache.RequestWrite(webRequest.url, copy); } } // Clean up. webRequest.Dispose(); CleanUpAfterWebRequest(bufferHolder); }
public void Generate() { var multigrid = new MultiGrid(Divisions, Dimensions, Offset, MinDistance, MaxDistance, colorRatio, colorIndex, colorIntersect); (poly, shapes, colors) = multigrid.Build(SharedVertices, randomize); if (shapes.Count == 0) { return; } if (ColorMethod == PolyHydraEnums.ColorMethods.ByTags) { float colorMin = colors.Min(); float colorMax = colors.Max(); for (var faceIndex = 0; faceIndex < poly.Faces.Count; faceIndex++) { var face = poly.Faces[faceIndex]; var colorIndex = colors[faceIndex]; float colorValue; switch (ColorFunction) { case ColorFunctions.Mod: colorValue = colorIndex % 1; break; case ColorFunctions.ActualMod: colorValue = PolyUtils.ActualMod(colorIndex, 1); break; case ColorFunctions.Normalized: colorValue = Mathf.InverseLerp(colorMin, colorMax, colorIndex); break; case ColorFunctions.Abs: colorValue = Mathf.Abs(colorIndex); break; default: colorValue = colorIndex; break; } string colorString = ColorUtility.ToHtmlStringRGB(ColorGradient.Evaluate(colorValue)); var tag = new Tuple <string, ConwayPoly.TagType>( $"#{colorString}", TagType); poly.FaceTags[faceIndex].Add(tag); } } if (ApplyOp) { var o1 = new OpParams { valueA = op1Amount1, valueB = op1Amount2, facesel = op1Facesel }; poly = poly.ApplyOp(op1, o1); var o2 = new OpParams { valueA = op2Amount1, valueB = op2Amount2, facesel = op2Facesel }; poly = poly.ApplyOp(op2, o2); var o3 = new OpParams { valueA = op3Amount1, valueB = op3Amount2, facesel = op3Facesel }; poly = poly.ApplyOp(op3, o3); } var mesh = PolyMeshBuilder.BuildMeshFromConwayPoly(poly, false, null, ColorMethod); GetComponent <MeshFilter>().mesh = mesh; }
private static ConwayPoly _MakeCupola(int sides, float height, bool bi = false, bool gyro = true) { sides = Mathf.Clamp(sides, 3, 64); ConwayPoly poly = _MakePolygon(sides * 2); Face bottom = poly.Faces[0]; ConwayPoly cap1 = _MakePolygon(sides, true, 0.25f, height, _CalcCupolaCapRadius(sides)); poly.Append(cap1); int i = 0; var squareSideFaces = new List <Face>(); var edge1 = poly.Halfedges[0]; var edge2 = poly.Halfedges[sides * 2]; while (true) { var side1 = new List <Vertex> { edge1.Next.Vertex, edge1.Vertex, edge2.Prev.Vertex }; poly.Faces.Add(side1); poly.FaceRoles.Add(ConwayPoly.Roles.New); poly.FaceTags.Add(new HashSet <Tuple <string, ConwayPoly.TagType> >()); var side2 = new List <Vertex> { edge1.Vertex, edge1.Prev.Vertex, edge2.Vertex, edge2.Prev.Vertex }; poly.Faces.Add(side2); squareSideFaces.Add(poly.Faces.Last()); poly.FaceRoles.Add(ConwayPoly.Roles.NewAlt); poly.FaceTags.Add(new HashSet <Tuple <string, ConwayPoly.TagType> >()); i++; edge1 = edge1.Next.Next; edge2 = edge2.Prev; if (i == sides) { break; } } if (bi) { float angleOffset = gyro ? 0.75f : 0.25f; ConwayPoly cap2 = _MakePolygon(sides, false, angleOffset, -height, _CalcCupolaCapRadius(sides)); poly.Append(cap2); i = 0; var middleVerts = bottom.GetVertices(); poly.Faces.Remove(bottom); poly.FaceRoles.RemoveAt(0); edge2 = poly.Faces.Last().Halfedge.Prev; int indexOffset = gyro ? 0 : -1; while (true) { var side1 = new List <Vertex> { middleVerts[PolyUtils.ActualMod(i * 2 - 1 + indexOffset, sides * 2)], middleVerts[PolyUtils.ActualMod(i * 2 + indexOffset, sides * 2)], edge2.Vertex }; poly.Faces.Add(side1); poly.FaceRoles.Add(ConwayPoly.Roles.New); poly.FaceTags.Add(new HashSet <Tuple <string, ConwayPoly.TagType> >()); var side2 = new List <Vertex> { middleVerts[PolyUtils.ActualMod(i * 2 + indexOffset, sides * 2)], middleVerts[PolyUtils.ActualMod(i * 2 + 1 + indexOffset, sides * 2)], edge2.Next.Vertex, edge2.Vertex, }; poly.Faces.Add(side2); poly.FaceRoles.Add(ConwayPoly.Roles.NewAlt); poly.FaceTags.Add(new HashSet <Tuple <string, ConwayPoly.TagType> >()); i++; edge2 = edge2.Next; if (i == sides) { break; } } } poly.Halfedges.MatchPairs(); return(poly); }