/// <summary> /// Selects a <see cref="DoubleArray"/> to another <see cref="DoubleArray"/>. The result is stored in a <see cref="Identity"/>. /// </summary> /// <param name="input">The indicator that sends data via <see cref="IUpdatable.Updated"/></param> /// <param name="selector">A selector to choose what <see cref="DoubleArray"/>.</param> /// <param name="waitForFirstToReady">Input must be ready in order to push the updates forward.</param> /// <param name="name">Name of the new returned <see cref="Identity"/>.</param> public static Identity Select(this IUpdatable input, ArraySelectorFunctionHandler selector, int outputCount = 1, int properties = 1, bool waitForFirstToReady = true, string name = null) { if (selector == null) { throw new ArgumentNullException(nameof(selector)); } outputCount = outputCount > 0 ? outputCount : input.OutputCount; var idn = new Identity(ResolveName(input, name), outputCount, properties); if (outputCount > 1) { unsafe { if (waitForFirstToReady) { input.Updated += (time, updated) => { if (input.IsReady) { var ret = new DoubleArray2DManaged(outputCount, properties); fixed(double *dst = ret, selectSrc = updated) for (int i = 0; i < updated.Count; i++) { var result = selector(selectSrc[i * updated.Properties]); Guard.AssertTrue(result.Count == outputCount, "Passed outputCount must be matching to the updated array."); Guard.AssertTrue(properties == result.Properties, "Properties must match the properties argument passed."); fixed(double *src = result) Unsafe.CopyBlock(dst + i, src, (uint)(result.LinearLength * sizeof(double))); } idn.Update(time, ret); } }; } else { input.Updated += (time, updated) => { var ret = new DoubleArray2DManaged(updated.Count, properties); fixed(double *dst = ret, selectSrc = updated) for (int i = 0; i < outputCount; i++) { var result = selector(selectSrc[i * updated.Properties]); Guard.AssertTrue(result.Count == outputCount, "Passed outputCount must be matching to the updated array."); Guard.AssertTrue(properties == result.Properties, "Properties must match the properties argument passed."); fixed(double *src = result) Unsafe.CopyBlock(dst, src, (uint)(result.LinearLength * sizeof(double))); } idn.Update(time, ret); }; } input.Resetted += sender => idn.Reset(); } } if (waitForFirstToReady) { input.Updated += (time, updated) => { if (input.IsReady) { idn.Update(time, selector(updated)); } }; } else { input.Updated += (time, updated) => idn.Update(time, selector(updated)); } input.Resetted += sender => idn.Reset(); return(idn); }
/// <summary> /// Performs a math <paramref name="op"/> over <see cref="DoubleArray"/> or the value from <paramref name="selector"/>. The result is stored in a <see cref="Identity"/>. /// </summary> /// <param name="first">The indicator that sends data via <see cref="IUpdatable.Updated"/> even to the math <paramref name="op"/></param> /// <param name="op">The operation to perform on the <see cref="DoubleArray"/> passed from <paramref name="first"/>.</param> /// <param name="selector">A selector to choose what <see cref="DoubleArray"/> to pass to math <paramref name="op"/>. By default, the unchanged <see cref="DoubleArray"/> is used.</param> /// <param name="waitForFirstToReady">First must be ready in order to push the updates forward.</param> /// <param name="name">Name of the new returned <see cref="Identity"/> representing the <paramref name="op"/>.</param> public static Identity Function(this IUpdatable first, UnaryArrayFunctionHandler op, ArraySelectorFunctionHandler selector = null, bool waitForFirstToReady = true, string name = null) { if (op == null) { throw new ArgumentNullException(nameof(op)); } var idn = new Identity(ResolveName(first, name)); if (selector == null) { if (waitForFirstToReady) { first.Updated += (time, updated) => { if (first.IsReady) { idn.Update(time, op(updated)); } }; } else { first.Updated += (time, updated) => idn.Update(time, op(updated)); } } else { if (waitForFirstToReady) { first.Updated += (time, updated) => { if (first.IsReady) { idn.Update(time, op(selector(updated))); } }; } else { first.Updated += (time, updated) => idn.Update(time, op(selector(updated))); } } first.Resetted += sender => idn.Reset(); return(idn); }