public static void WriteGenericToPtr <T>(IntPtr dest, T value, uint sizeOfT) where T : struct { Assure.False(dest == IntPtr.Zero); Assure.True(typeof(T).IsBlittable()); Assure.Equal(sizeOfT, (uint)SizeOf <T>()); byte * bytePtr = (byte *)dest; TypedReference valueref = __makeref(value); byte * valuePtr = (byte *)*((IntPtr *)&valueref); for (uint i = 0U; i < sizeOfT; ++i) { bytePtr[i] = valuePtr[i]; } }
public static Quaternion Parse(string quaternionString) { Assure.NotNull(quaternionString); try { string[] components = quaternionString.Trim('<', '>').Split('~'); Vector3 xyz = Vector3.Parse(components[0].Trim()); float w = float.Parse(components[1].Trim(), CultureInfo.InvariantCulture); return(new Quaternion(new Vector4(xyz, w: w))); } catch (Exception e) { throw new FormatException("Could not parse transform string.", e); } }
public static Vector2 Parse(string vectorString) { Assure.NotNull(vectorString); try { string[] numericComponents = vectorString.Trim('[', ']').Split(','); float x = float.Parse(numericComponents[0].Trim(), CultureInfo.InvariantCulture); float y = float.Parse(numericComponents[1].Trim(), CultureInfo.InvariantCulture); return(new Vector2(x, y)); } catch (Exception e) { throw new FormatException("Could not parse vector string.", e); } }
public void MasterWaitForClose() { Assure.Equal(Thread.CurrentThread, LosgapSystem.MasterThread); Monitor.Enter(barrierOpenLock); hydrateInvocationQueue: while (masterInvocationQueue.Count > 0) { PipelineMasterInvocation pmi; if (!masterInvocationQueue.TryDequeue(out pmi)) { continue; } try { if (pmi.IsSynchronousCall) { Monitor.Enter(pmi.InvocationCompleteMonitor); pmi.Action(); } else { pmi.Action(); } } catch (Exception e) { if (pmi.IsSynchronousCall) { pmi.RaisedException = e; } else { LosgapSystem.ExitWithError("Exception raised in asynchronous pipeline master invocation.", e); } } finally { if (pmi.IsSynchronousCall) { Monitor.Pulse(pmi.InvocationCompleteMonitor); Monitor.Exit(pmi.InvocationCompleteMonitor); } } } if (barrierOpen) { Monitor.Wait(barrierOpenLock); goto hydrateInvocationQueue; } Monitor.Exit(barrierOpenLock); }
public static Transform Parse(string transformString) { Assure.NotNull(transformString); try { string[] components = transformString.Trim('(', ')').Split('|'); Vector3 scale = Vector3.Parse(components[0].Split(':')[1].Trim()); Quaternion rotation = Quaternion.Parse(components[1].Split(':')[1].Trim()); Vector3 translation = Vector3.Parse(components[2].Split(':')[1].Trim()); return(new Transform(scale, rotation, translation)); } catch (Exception e) { throw new FormatException("Could not parse transform string.", e); } }
/// <summary> /// Copies data from the <paramref name="source"/> pointer to the <paramref name="destination"/> array. /// </summary> /// <typeparam name="T">The array element type. Must be a <see cref="Extensions.IsBlittable">blittable</see> struct.</typeparam> /// <param name="source">The pointer to the source data. Must not be <see cref="IntPtr.Zero"/>.</param> /// <param name="destination">The destination array to which the data will be copied. This method will copy /// <see cref="ArraySlice{T}.Length"/> elements' worth of data, starting at the <see cref="ArraySlice{T}.Offset"/>.</param> /// <param name="arrayElementSizeBytes">The size of <typeparamref name="T"/>. Use either sizeof() (preferred), or /// <see cref="SizeOf{T}"/> if the type is not known at compile-time.</param> public static unsafe void CopyGenericArray <T>(IntPtr source, ArraySlice <T> destination, uint arrayElementSizeBytes) where T : struct { Assure.False(source == IntPtr.Zero); Assure.True(typeof(T).IsBlittable()); Assure.Equal((int)arrayElementSizeBytes, SizeOf <T>()); GCHandle pinnedArrayHandle = GCHandle.Alloc(destination.ContainingArray, GCHandleType.Pinned); try { MemCopy(source, pinnedArrayHandle.AddrOfPinnedObject() + (int)(arrayElementSizeBytes * destination.Offset), destination.Length * arrayElementSizeBytes); } finally { pinnedArrayHandle.Free(); } }
public static void InsertAt <T>(this IList <T> @this, T indexObject, T elementToInsert) { if (@this == null) { throw new ArgumentNullException("this", "InsertAt called on a null IEnumerable<T>."); } #if DEBUG int index = @this.IndexOf(indexObject); Assure.GreaterThanOrEqualTo(index, 0, "'IndexObject' element is not actually in list 'this'."); @this.Insert(index, elementToInsert); #else @this.Insert(@this.IndexOf(indexObject), elementToInsert); #endif }
public void GetOrthogonals(out Vector3 outOrthogonalA, out Vector3 outOrthogonalB) { Assure.NotEqual(this, ZERO, "Can not find orthogonals to ZERO vector."); Vector3 rotated = (Vector3)(this * orthoMatX); if (this.Dot(rotated) > 0.6f) { rotated = (Vector3)(this * orthoMatY); } float length = Length; outOrthogonalA = (this * rotated).WithLength(length); outOrthogonalB = (this * outOrthogonalA).WithLength(length); }
/// <summary> /// Returns the Z co-ordinate of the requested <paramref name="corner"/> of this cuboid. /// </summary> /// <param name="corner">The corner whose position it is you wish to obtain.</param> /// <returns>The position on the Z-axis of the requested <paramref name="corner"/> of this cuboid.</returns> public float GetCornerZ(CuboidCorner corner) { Assure.True(Enum.IsDefined(typeof(CuboidCorner), corner), "Invalid corner constant: " + corner + " is not a valid CuboidCorner value."); switch (corner) { case CuboidCorner.BackTopLeft: case CuboidCorner.BackTopRight: case CuboidCorner.BackBottomLeft: case CuboidCorner.BackBottomRight: return(FrontBottomLeft.Z + Depth); default: return(FrontBottomLeft.Z); } }
/// <summary> /// Returns a rectangle describing the requested <paramref name="side"/> of this cuboid (transposed in to the 2D XY plane). /// </summary> /// <param name="side">The side that you wish to get a description of.</param> /// <returns>A <see cref="Rectangle"/> whose dimensions represent the requested <paramref name="side"/> /// of this cuboid.</returns> public Rectangle GetSide(CuboidSide side) { Assure.True(Enum.IsDefined(typeof(CuboidSide), side), "Invalid side constant: " + side + " is not a valid CuboidSide value."); switch (side) { case CuboidSide.Top: case CuboidSide.Bottom: return(new Rectangle((Vector2)FrontBottomLeft[0, 2], Width, Depth)); case CuboidSide.Left: case CuboidSide.Right: return(new Rectangle((Vector2)FrontBottomLeft[2, 1], Depth, Height)); default: return(new Rectangle((Vector2)FrontBottomLeft[0, 1], Width, Height)); } }
/// <summary> /// Sets the new location for the log file. If a file was already open, it should be flushed and closed before the new one is opened. /// </summary> /// <param name="filePath">The location of the new file to open.</param> /// <exception cref="ObjectDisposedException">Thrown if <see cref="ILoggingProvider.IsDisposed"/> is true.</exception> /// <exception cref="UnauthorizedAccessException">Thrown if the file could not be opened because the application does /// not have the relevant permissions.</exception> /// <exception cref="IOException">Thrown if the file could not be opened for writing.</exception> /// <exception cref="ArgumentException">Thrown if <paramref name="filePath"/> does not represent a valid file path.</exception> public virtual void SetLogFileLocation(string filePath) { lock (InstanceMutationLock) { if (IsDisposed) { throw new ObjectDisposedException("This logging provider has been disposed: Can not set new log file location!"); } if (!IOUtils.IsValidFilePath(filePath)) { throw new ArgumentException("'" + filePath + "' is not a valid file path!", "filePath"); } DisposeCurrentStream(); #if !RELEASE && !DEVELOPMENT try { currentFileStreamWriter = File.CreateText(filePath); } catch (Exception e) { Assure.Fail("Could not create log file at '" + filePath + "'. Exception: " + e.GetAllMessages()); throw; } #else currentFileStreamWriter = File.CreateText(filePath); #endif #if !RELEASE && !DEVELOPMENT string openingMessage = "Platform version " + LosgapSystem.Version + ", debug build"; #elif DEVELOPMENT string openingMessage = "Platform version " + LosgapSystem.Version + ", development build"; #else var version = Assembly.GetExecutingAssembly().GetName().Version; string openingMessage = "Build " + version.Build + "." + version.Revision; #endif currentFileStreamWriter.Write(LosgapSystem.ApplicationName + ", made by Egodystonic Studios " + "( http://www.escapelizards.com | http://www.egodystonic.com ) :: "); currentFileStreamWriter.WriteLine(openingMessage); currentFileStreamWriter.WriteLine("Installation directory set to " + LosgapSystem.InstallationDirectory.FullName + "."); currentFileStreamWriter.WriteLine("Mutable data directory set to " + LosgapSystem.MutableDataDirectory.FullName + "."); currentFileStreamWriter.WriteLine("Working directory is " + Environment.CurrentDirectory + "."); currentFileStreamWriter.WriteLine("Logical core count is " + Environment.ProcessorCount + "."); currentFileStreamWriter.WriteLine(); currentFileStreamWriter.Flush(); } }
public void False() { // Define variables and constants // Set up context // Execute Assure.False(false); try { Assure.False(true); Assert.Fail(); } catch (AssuranceFailedException) { } // Assert outcome }
public static T ReadGenericFromPtr <T>(IntPtr source, int sizeOfT) where T : struct { Assure.False(source == IntPtr.Zero); Assure.True(typeof(T).IsBlittable()); Assure.Equal(sizeOfT, (uint)SizeOf <T>()); byte *bytePtr = (byte *)source; T result = default(T); TypedReference resultRef = __makeref(result); byte * resultPtr = (byte *)*((IntPtr *)&resultRef); for (uint i = 0U; i < sizeOfT; ++i) { resultPtr[i] = bytePtr[i]; } return(result); }
/// <summary> /// Relinquishes permission for mutation, allowing state-freezing to happen. /// </summary> public void Dispose() { if (additionalLockObject != null) { Monitor.Exit(additionalLockObject); } lock (barrier.freezeLock) { #if DEBUG Assure.False(isDisposed, "Can not dispose same MutationPermit more than once!"); isDisposed = true; #endif --barrier.activeMutatorsCounter; if (barrier.activeMutatorsCounter == 0) { Monitor.PulseAll(barrier.freezeLock); } } }
public void Execute(int numAtomics, int blockSize, Action <int> atomicAction) { Assure.Equal(Thread.CurrentThread, LosgapSystem.MasterThread, "Execution of parallel processor should be from master thread."); Assure.NotNull(atomicAction); currentAction = atomicAction; currentBlockSize = blockSize; int numFullBlocks = numAtomics / blockSize; numReservableBlocks = numFullBlocks; currentWorkIsInvokeAllAction = false; bool singleThreadedMode = ForceSingleThreadedMode; if (!singleThreadedMode) { WorkBarrier.MasterOpenBarrier(); } // Do the 'odd-sized' ending block for (int i = blockSize * numFullBlocks; i < numAtomics; ++i) { atomicAction(i); } for (int blockIndex = Interlocked.Decrement(ref numReservableBlocks); blockIndex >= 0; blockIndex = Interlocked.Decrement(ref numReservableBlocks)) { int blockStartInc = currentBlockSize * blockIndex; int blockEndEx = currentBlockSize * (blockIndex + 1); for (int i = blockStartInc; i < blockEndEx; ++i) { currentAction(i); } } if (!singleThreadedMode) { WorkBarrier.MasterWaitForClose(); } }
public void SlaveWaitForReset() { Assure.NotEqual(Thread.CurrentThread, LosgapSystem.MasterThread); Monitor.Enter(barrierClosedLock); if (isDisposed) { Monitor.Exit(barrierClosedLock); return; } Monitor.Enter(barrierOpenLock); if (--slavesRemaining == 0U) { barrierOpen = false; Monitor.Pulse(barrierOpenLock); } Monitor.Exit(barrierOpenLock); Monitor.Wait(barrierClosedLock); Monitor.Exit(barrierClosedLock); }
public void TestGreaterThan() { // Define variables and constants const int THREE = 3; const int FOUR = 4; // Set up context // Execute Assure.GreaterThan(FOUR, THREE); try { Assure.GreaterThan(THREE, FOUR); Assert.Fail(); } catch (AssuranceFailedException) { } // Assert outcome }
public void TestLessThan() { // Define variables and constants const int FIVE = 5; const int FOUR = 4; // Set up context // Execute Assure.LessThan(FOUR, FIVE); try { Assure.LessThan(FIVE, FOUR); Assert.Fail(); } catch (AssuranceFailedException) { } // Assert outcome }
public void SlaveQueueOnMaster(PipelineMasterInvocation pmi) { Assure.NotNull(pmi); Assure.NotEqual(Thread.CurrentThread, LosgapSystem.MasterThread); Monitor.Enter(barrierOpenLock); masterInvocationQueue.Enqueue(pmi); Monitor.Pulse(barrierOpenLock); object externalLockObjLocal; lock (externalLockObjLock) { externalLockObjLocal = externalLockObj; } Monitor.Exit(barrierOpenLock); if (externalLockObjLocal != null) { Monitor.Enter(externalLockObjLocal); Monitor.PulseAll(externalLockObjLocal); Monitor.Exit(externalLockObjLocal); } }
internal MutationPermit(StateMutationBarrier barrier, object additionalLockObject) { Assure.NotNull(barrier); if (Monitor.IsEntered(barrier.freezeLock)) { throw new ApplicationException("Can not acquire permit: Mutations are locked from current thread."); } #if DEBUG isDisposed = false; #endif this.barrier = barrier; this.additionalLockObject = additionalLockObject; lock (barrier.freezeLock) { ++barrier.activeMutatorsCounter; } if (additionalLockObject != null) { Monitor.Enter(additionalLockObject); } }
/// <summary> /// Multiplies the two matrices. Remember that Matrix multiplication is not commutative. /// </summary> /// <param name="matA">The first matrix.</param> /// <param name="matB">The second matrix.</param> /// <param name="resultantDimension">The number of rows and columns in <paramref name="matA"/> and /// <paramref name="matB"/> that should be used in the multiplication calculation. The resultant matrix will /// also have this many rows and columns filled in.</param> /// <returns><paramref name="matA"/> x <paramref name="matB"/></returns> public static Matrix Multiply(Matrix matA, Matrix matB, int resultantDimension = 4) { Assure.BetweenOrEqualTo(resultantDimension, 1, 4, "Resultant dimension must be between 1 and 4."); switch (resultantDimension) { case 1: return(new Matrix(r0C0: Vector4.Dot(matA.RowA, matB.ColumnA))); case 2: return(new Matrix( r0C0: Vector4.Dot(matA.RowA, matB.ColumnA), r0C1: Vector4.Dot(matA.RowA, matB.ColumnB), r1C0: Vector4.Dot(matA.RowB, matB.ColumnA), r1C1: Vector4.Dot(matA.RowB, matB.ColumnB) )); case 3: Vector4 matBColA = matB.ColumnA; Vector4 matBColB = matB.ColumnB; Vector4 matBColC = matB.ColumnC; return(new Matrix( r0C0: Vector4.Dot(matA.RowA, matBColA), r0C1: Vector4.Dot(matA.RowA, matBColB), r0C2: Vector4.Dot(matA.RowA, matBColC), r1C0: Vector4.Dot(matA.RowB, matBColA), r1C1: Vector4.Dot(matA.RowB, matBColB), r1C2: Vector4.Dot(matA.RowB, matBColC), r2C0: Vector4.Dot(matA.RowC, matBColA), r2C1: Vector4.Dot(matA.RowC, matBColB), r2C2: Vector4.Dot(matA.RowC, matBColC) )); case 4: return(matA * matB); default: Logger.Warn("Matrix.Multiply called with resultantDimension of: " + resultantDimension + "!"); return(ZERO); } }
public void TestBetweenOrEqualTo() { // Define variables and constants const int FIVE = 5; const int FOUR = 4; const int THREE = 3; // Set up context // Execute Assure.BetweenOrEqualTo(FOUR, THREE, FIVE); Assure.BetweenOrEqualTo(FOUR, FOUR, FIVE); try { Assure.BetweenOrEqualTo(THREE, FOUR, FIVE); Assert.Fail(); } catch (AssuranceFailedException) { } // Assert outcome }
/// <summary> /// Invokes the given <paramref name="action"/> on all slave threads, and also the master thread (invoking thread) if /// <paramref name="includeMaster"/> is <c>true</c>. /// </summary> /// <remarks>This method can only be invoked from the <see cref="LosgapSystem.MasterThread"/>.</remarks> /// <param name="action">The action to invoke on all threads. Must not be null.</param> /// <param name="includeMaster">True if this action should be executed by the calling (master) thread as well.</param> public void InvokeOnAll(Action action, bool includeMaster) { Assure.Equal(Thread.CurrentThread, LosgapSystem.MasterThread, "Invocation of parallel processor should be from master thread."); Assure.NotNull(action); currentInvokeAllAction = action; currentWorkIsInvokeAllAction = true; bool singleThreadedMode = ForceSingleThreadedMode; if (!singleThreadedMode) { WorkBarrier.MasterOpenBarrier(); } if (includeMaster) { currentInvokeAllAction(); } if (!singleThreadedMode) { WorkBarrier.MasterWaitForClose(); } }
public void TestNone() { // Define variables and constants IEnumerable <int> passingCollection = new[] { 1, 2, 7, 31, 99, 12 }; IEnumerable <int> failingCollection = new[] { 5, 136, 136, 76, 8, 32, 0 }; // Set up context // Execute Assure.None(passingCollection, i => i <= 0); try { Assure.None(failingCollection, i => i <= 0); Assert.Fail(); } catch (AssuranceFailedException) { } // Assert outcome }
/// <summary> /// Returns the determinant of this Matrix, used to calculate the <see cref="Cofactor"/> and <see cref="Inverse"/>. /// </summary> /// <param name="dimension">The number of rows and columns in this matrix to use in the determinant calculation.</param> /// <returns>The determinant of this matrix.</returns> public float GetDeterminant(int dimension = 4) { Assure.BetweenOrEqualTo(dimension, 1, 4, "Input dimension must be between 1 and 4."); switch (dimension) { case 1: return(RowA.X); case 2: return(RowA.X * RowB.Y - RowA.Y * RowB.X); case 3: return(RowA.X * (RowB.Y * RowC.Z - RowB.Z * RowC.Y) - RowA.Y * (RowB.X * RowC.Z - RowB.Z * RowC.X) + RowA.Z * (RowB.X * RowC.Y - RowB.Y * RowC.X)); default: return (RowA.X * GetMinor(0, 0).GetDeterminant(3) - RowA.Y * GetMinor(0, 1).GetDeterminant(3) + RowA.Z * GetMinor(0, 2).GetDeterminant(3) - RowA.W * GetMinor(0, 3).GetDeterminant(3)); } }
/// <summary> /// Fills the memory at the given <paramref name="dest"/> address with <paramref name="numBytes"/> zeroes. /// </summary> /// <param name="dest">The destination address. Must not be <see cref="IntPtr.Zero"/>.</param> /// <param name="numBytes">The number of bytes from <paramref name="dest"/> to fill with zeroes.</param> public static void ZeroMem(IntPtr dest, uint numBytes) { Assure.NotEqual(dest, IntPtr.Zero, "Destination address must not be Zero."); RtlZeroMemory(dest, new IntPtr(numBytes)); }
public virtual void WriteMessage(LogMessageSeverity messageSeverity, string message, Exception associatedException, string callerMemberName, string callerFilePath, int callerLineNumber) { Assure.NotNull(message); Assure.NotNull(callerMemberName); Assure.NotNull(callerFilePath); message = message.Replace(Environment.NewLine, Environment.NewLine + STACK_TRACE_LINE_PREFIX); lock (InstanceMutationLock) { if (IsDisposed) { return; // Safest option: No point throwing exceptions if some random component elicits a warning on shutdown } if (currentFileStreamWriter == null) { throw new InvalidOperationException("Can not write log line: No log file location has successfully been set on this logging provider!"); } logLineBuilder.Clear(); if (AddTimestamps) { logLineBuilder.Append(DateTime.Now.ToString(TIMESTAMP_FORMAT)); logLineBuilder.Append("\t"); } switch (messageSeverity) { case LogMessageSeverity.Standard: logLineBuilder.Append(STANDARD_LOG_PREFIX); break; case LogMessageSeverity.Debug: logLineBuilder.Append(DEBUG_LOG_PREFIX); break; case LogMessageSeverity.Warning: logLineBuilder.Append(WARNING_LOG_PREFIX); break; case LogMessageSeverity.Fatal: logLineBuilder.Append(FATAL_LOG_PREFIX); break; } logLineBuilder.Append(message); if (AppendCaller) { logLineBuilder.Append(" <= "); logLineBuilder.Append(callerMemberName); if (IncludeDetailedCallerInfo) { logLineBuilder.Append("() in "); logLineBuilder.Append(Path.GetFileName(callerFilePath)); logLineBuilder.Append(":"); logLineBuilder.Append(callerLineNumber); } else { logLineBuilder.Append("()"); } } if (associatedException != null) { logLineBuilder.AppendLine(); associatedException.ForEachException(e => { logLineBuilder.Append(ASSOCIATED_EXCEPTION_PREFIX); logLineBuilder.AppendLine(associatedException.GetAllMessages(true).Replace(Environment.NewLine, " ")); if (e is ExternalException) { logLineBuilder.Append(STACK_TRACE_LINE_PREFIX); logLineBuilder.AppendLine("** External exception code: 0x" + (e as ExternalException).ErrorCode.ToString("x").ToUpper()); } if (e.StackTrace != null) { foreach (string line in e.StackTrace.Split(Environment.NewLine) .Select(line => line.Trim()) .Where(line => !line.IsNullOrWhiteSpace())) { logLineBuilder.Append(STACK_TRACE_LINE_PREFIX); logLineBuilder.AppendLine(line); } } else { logLineBuilder.Append(STACK_TRACE_LINE_PREFIX); logLineBuilder.AppendLine("<No stack trace>"); } }); } logLineBuilder.AppendLine(); #if !RELEASE && !DEVELOPMENT try { currentFileStreamWriter.Write(logLineBuilder); currentFileStreamWriter.Flush(); } catch (Exception e) { Assure.Fail("Could not write message to log file. Exception: " + e.GetAllMessages()); throw; } #else currentFileStreamWriter.Write(logLineBuilder); currentFileStreamWriter.Flush(); #endif BroadcastMessage(messageSeverity, message, associatedException); } }
/// <summary> /// Returns the projection of this vector on the given <paramref name="axis"/> vector (needs not be a primary world axis). /// </summary> /// <param name="axis">The axis to project on to.</param> /// <returns>A new Vector that is the the equivalent part of this vector that 'points' along the <paramref name="axis"/> /// vector.</returns> public Vector4 ProjectedOnto(Vector4 axis) { Assure.NotEqual(axis, ZERO, "Can not project on to zero vector."); axis = axis.ToUnit(); return(Dot(this, axis) * axis); }
/// <summary> /// Test whether this object is equal to <paramref name="other"/> within a given <paramref name="tolerance"/>. Even if the /// two structures are not identical, this method will return <c>true</c> if they are 'close enough' (e.g. within the tolerance). /// </summary> /// <param name="other">The other Circle to test against.</param> /// <param name="tolerance">The amount of tolerance to give. For any floating-point component in both objects, if the difference /// between them is less than this value, they will be considered equal.</param> /// <returns>True if this object is equal to <paramref name="other"/> with the given <paramref name="tolerance"/>.</returns> public bool EqualsWithTolerance(Circle other, double tolerance) { Assure.GreaterThanOrEqualTo(tolerance, 0f, "Tolerance must not be negative."); return(Center.EqualsWithTolerance(other.Center, tolerance) && Math.Abs(Radius - other.Radius) < tolerance); }
/// <summary> /// Gets the radius of the circle taken by slicing through this sphere at the given distance from its centre. /// </summary> /// <param name="distanceFromCentre">The distance from the centre to get the slice's radius for.</param> /// <returns>The radius of the circle at the given distance from the sphere's centre.</returns> /// <exception cref="AssuranceFailedException">Thrown if <paramref name="distanceFromCentre"/> is greater than /// <see cref="Radius"/>.</exception> public float GetRadius(float distanceFromCentre) { Assure.LessThanOrEqualTo(distanceFromCentre, Radius, "Distance from centre must be smaller than or equal to the sphere radius!"); return((float)Math.Sqrt((Radius * Radius) - (distanceFromCentre * distanceFromCentre))); }