diff --git a/Dali.Toolkit/Dali.Toolkit.csproj b/Dali.Toolkit/Dali.Toolkit.csproj new file mode 100644 index 0000000..207b449 --- /dev/null +++ b/Dali.Toolkit/Dali.Toolkit.csproj @@ -0,0 +1,26 @@ + + + Dali + Dali + Copyright 2018 (c) INSA Rennes. All Right reserved. + Éric Anquetil + netstandard2.0 + true + 1.1.167 + 1.1.167 + 1.1.167 + Debug;Release;ReleaseObfuscated + + + + + 2.0 + + + + + + + + + diff --git a/Dali.Toolkit/DaliStroke.cs b/Dali.Toolkit/DaliStroke.cs new file mode 100644 index 0000000..81cf955 --- /dev/null +++ b/Dali.Toolkit/DaliStroke.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace DALI.ToolKit +{ + public class DaliStroke : IEnumerable + { + public Guid Id { get; private set; } = Guid.NewGuid(); + + private IEnumerable _points; + + public DaliStroke(IEnumerable points) + { + _points = points.ToList(); + } + + public IEnumerator GetEnumerator() + { + return _points.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _points.GetEnumerator(); + } + } +} diff --git a/Dali.Toolkit/DaliStrokePoint.cs b/Dali.Toolkit/DaliStrokePoint.cs new file mode 100644 index 0000000..cfdda52 --- /dev/null +++ b/Dali.Toolkit/DaliStrokePoint.cs @@ -0,0 +1,79 @@ +using System; +namespace DALI.ToolKit +{ + public struct DaliStrokePoint: ICloneable + { + public DaliStrokePoint(double x, double y) + { + X = x; + Y = y; + T = TimeSpan.MaxValue; + P = 0.5; + } + + public DaliStrokePoint(double x, double y, TimeSpan t, double p) + { + X = x; + Y = y; + P = p; + T = t; + } + + public bool IsCoordinatesOnly { get => T == TimeSpan.MaxValue && P == 0.5; } + + public double X { get; set; } + public double Y { get; set; } + public double P { get; set; } + public TimeSpan T { get; set; } + + public override string ToString() + { + return string.Format("[DaliStrokePoint: X={0}, Y={1}, P={2}, T={3}]", X, Y, P, T); + } + + public override bool Equals(object obj) + { + if (!(obj is DaliStrokePoint)) + return false; + + DaliStrokePoint ds = (DaliStrokePoint)obj; + + double epsylon = 0.01; + + var diffX = Math.Abs(ds.X - this.X); + var diffY = Math.Abs(ds.Y - this.Y); + + if (diffX < epsylon && diffY < epsylon) + { + return true; + } + else + return false; + } + + public bool EqualsEpsylon(DaliStrokePoint ds, double epsylon) + { + var diffX = Math.Abs(ds.X - this.X); + var diffY = Math.Abs(ds.Y - this.Y); + + if (diffX < epsylon && diffY < epsylon) + { + return true; + } + else + return false; + } + + public override int GetHashCode() + { + return this.GetHashCode(); + } + + public object Clone() + { + return this.MemberwiseClone(); + } + } + + +} diff --git a/Dali.Toolkit/IO/InkmlExtensions.cs b/Dali.Toolkit/IO/InkmlExtensions.cs new file mode 100644 index 0000000..e756fab --- /dev/null +++ b/Dali.Toolkit/IO/InkmlExtensions.cs @@ -0,0 +1,48 @@ +using DALI.ToolKit; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace DALI.ToolKit.IO +{ + public static class InkmlExtensions + { + static readonly string inkmlPointFormat = "{0:0.####} {1:0.####}"; + static readonly string inkmlPointFormatPressure = "{0:0.####} {1:0.####} {2:0.####}"; + static readonly string inkmlPointFormatPressureTime = "{0:0.####} {1:0.####} {2:0.####} {3:0}"; + static readonly string inkmlSeparator = ", "; + + public static string ToInkml(this IEnumerable trace, bool pressure = true) + { + return String.Join(inkmlSeparator, trace.Select(p => p.ToInkml(pressure))); + } + + public static string ToInkml(this DaliStrokePoint point, bool pressure = true) + { + if (pressure) + { + return String.Format(CultureInfo.InvariantCulture, inkmlPointFormatPressureTime, point.X, point.Y, point.P, point.T.TotalMilliseconds); + } + else + return String.Format(CultureInfo.InvariantCulture, inkmlPointFormat, point.X, point.Y); + } + + public static DaliStroke ToTrace(this string inkml, DateTime? startTime = null) + { + return new DaliStroke(inkml.Split(',').Select(ps => InkmlExtensions.ToTracePoint(ps)));//.ToTrace(startTime); + } + + public static DaliStrokePoint ToTracePoint(this string inkml, bool isPenUp = false) + { + var split = inkml.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + + if (split.Length == 4) + return new DaliStrokePoint(Double.Parse(split[0], CultureInfo.InvariantCulture), Double.Parse(split[1], CultureInfo.InvariantCulture), TimeSpan.FromMilliseconds(Int32.Parse(split[3])), Single.Parse(split[2], CultureInfo.InvariantCulture)); + else + throw new InvalidOperationException("Wrong format " + inkml); + } + + } +} diff --git a/Dali.Toolkit/IO/InkmlFile.cs b/Dali.Toolkit/IO/InkmlFile.cs new file mode 100644 index 0000000..79aac88 --- /dev/null +++ b/Dali.Toolkit/IO/InkmlFile.cs @@ -0,0 +1,78 @@ +using DALI.ToolKit; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; + +namespace DALI.ToolKit.IO +{ + /// + /// InkmlFile use for Architecture project + /// + /// To do : refactoring for more generic type (Geometry, Architecture ...) + /// + public class InkmlFile + { + string filepath; + Dictionary pool = new Dictionary(); + List inputs = new List(); + + public InkmlFile(string filepath) + { + this.filepath = filepath; + Name = Path.GetFileName(filepath); + } + + public string Name + { get; private set; } + + public string Filepath + { get { return filepath; } } + + public IEnumerable Inputs { get { return inputs; } } + + public void Load() + { + var doc = new XmlDocument(); + doc.Load(filepath); + + XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); + manager.AddNamespace("i", @"http://www.w3.org/2003/InkML"); + + // discard annotations + /* foreach (XmlNode annotation in doc.SelectNodes("i:ink/i:annotation", manager)) + { + var key = annotation.Attributes["type"].InnerText; + + annotations.Add(new Annotation(key, annotation.InnerText)); + }*/ + + foreach (XmlNode stroke in doc.SelectNodes("i:ink/i:trace", manager)) + { + var id = stroke.Attributes["id"].InnerText; + + if (stroke.Attributes["timeOffset"] != null) + { + long timeOffsetParsed; + if (Int64.TryParse(stroke.Attributes["timeOffset"].InnerText, out timeOffsetParsed)) + { + var timeOffset = Input.DateTimeFromUnixMilliSeconds(timeOffsetParsed); + pool.Add(id, InkmlExtensions.ToTrace(stroke.InnerText, timeOffset)); + } + } + else + { + pool.Add(id, InkmlExtensions.ToTrace(stroke.InnerText)); + } + } + + foreach (XmlNode node in doc.SelectNodes("i:ink/i:traceGroup", manager)) + { + Input input = new Input(node, manager, pool); + + inputs.Add(input); + } + } + } +} diff --git a/Dali.Toolkit/IO/Input.cs b/Dali.Toolkit/IO/Input.cs new file mode 100644 index 0000000..c487482 --- /dev/null +++ b/Dali.Toolkit/IO/Input.cs @@ -0,0 +1,151 @@ +using DALI.ToolKit; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace DALI.ToolKit.IO +{ + public class Input + { + static readonly DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0); + + public static DateTime DateTimeFromUnixMilliSeconds(long timestamp) + { + return unixEpoch.AddMilliseconds(timestamp); + } + + List traces = new List(); + + public Input(XmlNode node, XmlNamespaceManager manager, Dictionary pool) + { + Id = String.Empty; + + var attr = node.Attributes["xml:id"]; + if (attr != null) + Id = attr.InnerText; + + var attrTimeOffset = node.Attributes["timeOffset"]; + if (attrTimeOffset != null) + { + long timeOffsetParsed; + if (Int64.TryParse(attrTimeOffset.InnerText, out timeOffsetParsed)) + TimeOffset = timeOffsetParsed; + } + + /** discard annotations */ + /*foreach (XmlNode annotation in node.SelectNodes("i:annotation", manager)) + { + var key = annotation.Attributes["type"].InnerText; + annotations.Add(new Annotation(key, annotation.InnerText)); + } + */ + /* discard traceview */ + /* foreach (XmlNode view in node.SelectNodes("i:traceView", manager)) + { + var dataref = view.Attributes["traceDataRef"].InnerText; + if (pool.ContainsKey(dataref)) + traces.Add(pool[dataref]); + else + refs.Add(new Reference() { ReferenceId = dataref }); + + }*/ + foreach (XmlNode trace in node.SelectNodes("i:trace", manager)) + { + var traceType = trace.Attributes["type"]; + var traceErased = trace.Attributes["erased"]; + bool isPenUpTrace = traceType != null && String.Equals(traceType.Value, "penUp"); + bool isErasedTrace = traceErased != null && String.Equals(traceErased.Value, "true"); + + + if (trace.Attributes["timeOffset"] != null) + { + long timeOffsetParsed; + if (Int64.TryParse(trace.Attributes["timeOffset"].InnerText, out timeOffsetParsed)) + { + var timeOffset = DateTimeFromUnixMilliSeconds(timeOffsetParsed); + traces.Add(InkmlExtensions.ToTrace(trace.InnerText, timeOffset)); + } + } + else + { + traces.Add(InkmlExtensions.ToTrace(trace.InnerText)); + } + + } + } + + public Input(string id, IEnumerable traces) + { + Id = id; + + this.traces = new List(traces); + } + + private string id; + public string Id + { + get + { + return id; + } + set + { + id = value; + + } + } + + private long timeOffset; + public long TimeOffset + { + get + { + return timeOffset; + } + set + { + timeOffset = value; + } + } + + public IList Traces + { + get { return traces; } + set + { + traces.Clear(); + foreach (var trace in value) + traces.Add(trace); + } + } + + public event EventHandler DeleteRequested; + + //ICommand extract; + //public ICommand Extract + //{ + // get + // { + // if (extract == null) + // extract = new RelayCommand(() => + // { + // strokefeatures.Clear(); + // foreach (var trace in traces) + // { + // strokefeatures.Add(extractor.Extract(getPoints(trace)).ToList()); + // } + + + // features = extractor.Extract(getPoints()).ToList(); + + // RaisePropertyChanged(vm => vm.Features); + // RaisePropertyChanged(vm => vm.StrokeFeatures); + + // }); + // return extract; + // } + //} + } +} diff --git a/Dali.Toolkit/Utils/ContainerSingleton.cs b/Dali.Toolkit/Utils/ContainerSingleton.cs new file mode 100644 index 0000000..cb976f5 --- /dev/null +++ b/Dali.Toolkit/Utils/ContainerSingleton.cs @@ -0,0 +1,24 @@ +using Autofac; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DALI.Utils +{ + /// + /// Container for Autofac for Dali engine + /// + public class ContainerSingleton + { + public static IContainer Container { get; private set; } + public static ILifetimeScope Scope { get; private set; } + + public ContainerSingleton(IContainer container) + { + Container = container; + Scope = container.BeginLifetimeScope(); + } + } +} diff --git a/Dali.Toolkit/Utils/NamePoint.cs b/Dali.Toolkit/Utils/NamePoint.cs new file mode 100644 index 0000000..243a1e2 --- /dev/null +++ b/Dali.Toolkit/Utils/NamePoint.cs @@ -0,0 +1,184 @@ +using System; +using System.Linq; + +namespace DALI.Toolkit.Utils +{ + /// + /// Value name for a point + /// + public class NamePoint : IEquatable + { + public char Letter { get; set; } + public int Index { get; set; } + public bool HavePrime { get; set; } + + public NamePoint() + { + Letter = '*'; + Index = 0; + HavePrime = false; + } + + public NamePoint(string name) + { + if (name.Length > 0) + { + Letter = name.First(); + + char lastChar = name.Last(); + + if (lastChar.ToString().Equals(ParamNamePoint.PrimeValue)) + { + HavePrime = true; + } + else + { + HavePrime = false; + } + + if (HavePrime) + { + //Case A' + if (name.Length <= 2) + { + Index = 0; + } + //Cas A1' + else + { + string indexString = name.Substring(1, name.Length - 2); + Index = Int32.Parse(indexString); + } + } + else + { + //Case A + if (name.Length <= 1) + { + Index = 0; + } + //Case A1 + else + { + string indexString = name.Substring(1, name.Length - 1); + Index = Int32.Parse(indexString); + } + } + } + else + { + throw new Exception("Error name empty for point"); + } + } + + /// + /// Allow to sorted => A A' B B' A1 B1 + /// + /// + /// + public bool NameIsStrictUpTo(NamePoint nametoCompate) + { + if (this.Index > nametoCompate.Index) + { + return true; + } + else if (this.Index == nametoCompate.Index) + { + if (this.Letter != nametoCompate.Letter) + { + if (this.Letter < nametoCompate.Letter) + { + return false; + } + else + { + return true; + } + } + else + { + //A1 and A1' + if (this.HavePrime && !nametoCompate.HavePrime) + { + return true; + } + else + { + return false; + } + } + } + else + { + return false; + } + + } + + public NamePoint GetNextName() + { + char nextLetter = Letter; + + if(nextLetter == 'Z') + { + nextLetter = 'A'; + int nextIndex = Index + 1; + + string nextName = nextLetter.ToString() + nextIndex; + + return new NamePoint(nextName); + } + else + { + nextLetter++; + + string nextName = nextLetter.ToString() + Index; + + return new NamePoint(nextName); + } + } + + public override string ToString() + { + if(Index != 0) + { + if(HavePrime) + { + return Letter.ToString() + Index + ParamNamePoint.PrimeValue; + } + else + { + return Letter.ToString() + Index; + } + } + else + { + if (HavePrime) + { + return Letter.ToString() + ParamNamePoint.PrimeValue; + } + else + { + return Letter.ToString(); + } + } + } + + public override int GetHashCode() + { + return Letter.GetHashCode() + Index.GetHashCode() + HavePrime.GetHashCode(); + } + + public bool Equals(NamePoint other) + { + if (this.Letter == other.Letter && this.Index == other.Index && this.HavePrime.Equals(other.HavePrime)) + { + return true; + } + else + { + return false; + } + } + } +} diff --git a/Dali.Toolkit/Utils/ParamNamePoint.cs b/Dali.Toolkit/Utils/ParamNamePoint.cs new file mode 100644 index 0000000..fb8d655 --- /dev/null +++ b/Dali.Toolkit/Utils/ParamNamePoint.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DALI.Toolkit.Utils +{ + /// + /// Define constant for Name Point => to avoid typo mystake + /// + public static class ParamNamePoint + { + //Param for prime for name point + public const string PrimeValue = "'"; + } +} diff --git a/Dali.Toolkit/Utils/ParamSegmentation.cs b/Dali.Toolkit/Utils/ParamSegmentation.cs new file mode 100644 index 0000000..2f7b40d --- /dev/null +++ b/Dali.Toolkit/Utils/ParamSegmentation.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DALI.Utils +{ + /// + /// Define param for each segmentor + /// + public static class ParamSegmentation + { + //Param for Douglas Peucker segmentor + public const Double ToleranceDouglasPeucker =10; + //Angle Param for Douglas Peucker segmentor, to retreive angular points + public const Double AngularTolerance = 150; + public const Double NbSegmentationMax = 7; + } +} diff --git a/Dali.Toolkit/Utils/VerticesName.cs b/Dali.Toolkit/Utils/VerticesName.cs new file mode 100644 index 0000000..e3e3e97 --- /dev/null +++ b/Dali.Toolkit/Utils/VerticesName.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace DALI.Toolkit.Utils +{ + public class VerticesName + { + private SortedDictionary _names; + + public static VerticesName _instance = null; + + public static VerticesName Instance + { + get + { + if (_instance == null) + { + _instance = new VerticesName() + { + _names = new SortedDictionary(new SortNamePointComparer()) + }; + + } + + return _instance; + } + } + + public VerticesName() + { + } + + public string GetNextNamePoint(bool addNextName) + { + if (_names.Count == 0) + { + NamePoint first = new NamePoint("A"); + + if (addNextName) + { + _names.Add(first, 1); + } + + return first.ToString(); + } + else + { + var last = _names.Last().Key; + NamePoint nextName = last.GetNextName(); + + if (addNextName) + { + _names.Add(nextName, 1); + } + + return nextName.ToString(); + } + } + + public void AddName(string name) + { + NamePoint n = new NamePoint(name); + + if (_names.ContainsKey(n)) + { + var newCountName = _names[n]; + newCountName++; + + _names[n] = newCountName; + } + else + { + _names.Add(n, 1); + } + } + + public void AddNameSubSegment(string name) + { + NamePoint n = new NamePoint(name); + + if (_names.ContainsKey(n)) + { + } + else + { + _names.Add(n, 1); + } + } + + public void RemoveName(string name) + { + NamePoint n = new NamePoint(name); + + if (_names.ContainsKey(n)) + { + var countName = _names[n]; + countName--; + + if (countName == 0) + { + _names.Remove(n); + } + } + } + + public void ResetCounter() + { + _names.Clear(); + } + } + + public class SortNamePointComparer : IComparer + { + public int Compare(NamePoint n1, NamePoint n2) + { + if(n1.NameIsStrictUpTo(n2)) + { + return 1; + } + else if(n1.Equals(n2)) + { + return 0; + } + else + { + return -1; + } + } + } +} diff --git a/README.md b/README.md index 7d3ce10..240bd11 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Simply run the build script More advanced usage: -> Context: You want to build a library named `AwesomeFeature` for Android only, and you have the Android NDK installed in `$ANDROID_NDK_ROOT` but not in `$ANDROID_NDK_HOME`. +> Context: You want to build a library named `AwesomeFeature` for Android only, and you have the Android NDK installed in `$ANDROID_NDK_ROOT` but not in `$ANDROID_NDK_HOME` . ```bash ./build.sh -i AwesomeFeature --ndk $ANDROID_NDK_ROOT --no-ios @@ -40,14 +40,15 @@ Usage: ./build.sh [options] Options: -h, --help Print this help and exit -i Input project name (required) - -g Generated project name (default: .Generated) + -g Generated project name (default: . Generated) -o Output folder name (default: libs) -y Assume yes to all prompts --ndk Android NDK path (default: ANDROID_NDK_HOME environment variable) --no-android Disable Android build (default: false) --no-ios Disable iOS build (default: false) - --input-spec Input project .NET spec (default: net8.0) - --output-spec Output project .NET spec (default: net8.0) + --input-spec Input project . NET spec (default: net8.0) + --output-spec Output project . NET spec (default: net8.0) + ``` ## What is this? @@ -62,3 +63,40 @@ This script: * iOS: * Run `beyondnetgen` and follow full process to get xframework * Copy the generated files to the output folder + +## Notes for external dependencies + +Sometimes, you need to use external dependencies in your library. For example, your library may use Autofac or Newtonsoft.Json. + +In this case, you need to add the dependencies as **DLL assemblies** in the `external` folder. + +> **Warning** You must modify the csproj of the original library to reference the external dependencies. + +```xml + + + + + +``` + +Then during the build, the script will automatically add the external dependencies to the generated project. + +### iOS + +For iOS you also need to add path to each dll in `template.beyondnetgen.ios.config.json`: + +```json +{ + "AssemblyPath": "INPUT_PROJECT_NAME/bin/Release/INPUT_NET_SPEC/INPUT_PROJECT_NAME.dll", + "CSharpUnmanagedOutputPath": "GENERATED_PROJECT_NAME/Generated.cs", + "COutputPath": "GENERATED_PROJECT_NAME/Generated.h", + // Add this + "AssemblySearchPaths": [ + "external/Autofac.dll" + ], + "Build": { + "Target": "apple-universal" + } +} +``` diff --git a/build.sh b/build.sh index 0b143df..922f4d2 100755 --- a/build.sh +++ b/build.sh @@ -98,6 +98,19 @@ build_android() { cd $generated_project_dir + # For each .dll in external folder add it as a reference in the generated project + search_dir="$script_dir/external" + for entry in "$search_dir"/*; do + dll_name=$(basename $entry) + log "Adding reference to $dll_name" + # Add reference to the generated project by editing the csproj file + # Search for the line + # and add a reference to the dll below it + sed -i '' "//a \\ + \\ +" "$generated_project_dir/$generated_project_name.csproj" + done + declare -A abis abis["arm64"]="arm64-v8a" abis["x64"]="x86_64" diff --git a/external/Autofac.dll b/external/Autofac.dll new file mode 100644 index 0000000..d5c1422 Binary files /dev/null and b/external/Autofac.dll differ diff --git a/template.beyondnetgen.ios.config.json b/template.beyondnetgen.ios.config.json index c0ea71c..10bc2b8 100644 --- a/template.beyondnetgen.ios.config.json +++ b/template.beyondnetgen.ios.config.json @@ -2,9 +2,6 @@ "AssemblyPath": "INPUT_PROJECT_NAME/bin/Release/INPUT_NET_SPEC/INPUT_PROJECT_NAME.dll", "CSharpUnmanagedOutputPath": "GENERATED_PROJECT_NAME/Generated.cs", "COutputPath": "GENERATED_PROJECT_NAME/Generated.h", - "AssemblySearchPaths": [ - "MathLib/bin/Release/net8.0/publish/MathLib.dll" - ], "Build": { "Target": "apple-universal" } diff --git a/template.csproj b/template.csproj index 4b23c1a..17645b1 100644 --- a/template.csproj +++ b/template.csproj @@ -90,7 +90,7 @@ - +