using Newtonsoft.Json; using REST_JSON_API; using System.Collections.Generic; using System.Linq; using System; using UnityEngine; using System.Collections; /// <summary> /// Point in 3D Space /// </summary> public class PointFact : FactWrappedCRTP<PointFact> { /// <summary> Position </summary> public Vector3 Point; /// <summary> Orientation for <see cref="Fact.WorldRepresentation"/> </summary> [JsonProperty] private Vector3 Normal; /// <summary> \copydoc Fact.Fact </summary> public PointFact() : base() { this.Point = Vector3.zero; this.Normal = Vector3.up; } /// <summary> /// Standard Constructor: /// Initiates <see cref="Point"/>, <see cref="Normal"/>, <see cref="Fact._URI"/> and creates MMT %Fact Server-Side /// </summary> /// <param name="P">sets <see cref="Point"/></param> /// <param name="N">sets <see cref="Normal"/></param> /// <param name="organizer">sets <see cref="Fact._Facts"/></param> public PointFact(Vector3 P, Vector3 N, FactRecorder organizer) : base(organizer) { this.Point = P; this.Normal = N; } protected override void RecalculateTransform() { Position = Point; { // Rotation Vector3 notNormal = Vector3.forward != Normal ? Vector3.forward : Vector3.up; Rotation = Quaternion.LookRotation( Vector3.Cross(Normal, notNormal), Normal ); } } /// <summary> /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_. /// <see cref="Normal"/> set to <c>Vector3.up</c> /// </summary> /// <param name="point">sets <see cref="Point"/></param> /// <param name="uri">MMT URI</param> /// <param name="organizer">sets <see cref="Fact._Facts"/></param> public PointFact(Vector3 point, SOMDoc _ServerDefinition, FactRecorder organizer) : base(organizer) { this.Point = point; this.Normal = Vector3.up; this.ServerDefinition = _ServerDefinition; _ = this.Label; } /// \copydoc Fact.parseFact(ScrollFact) public new static IEnumerator parseFact(List<Fact> ret, MMTFact fact) { if (((MMTGeneralFact)fact).defines is not OMA defines) yield break; ParsingDictionary.parseTermsToId.TryAdd(defines.ToString(), fact.@ref.uri); Vector3 point = SOMDoc.MakeVector3(defines); ret.Add(new PointFact(point, fact.@ref, StageStatic.stage.factState)); } /// \copydoc Fact.hasDependentFacts public override bool HasDependentFacts => false; /// \copydoc Fact.getDependentFactIds protected override string[] GetDependentFactIds() => new string[] { }; /// \copydoc Fact.GetHashCode public override int GetHashCode() => this.Point.GetHashCode(); /// \copydoc Fact.Equivalent(Fact, Fact) protected override bool EquivalentWrapped(PointFact f1, PointFact f2) => Math3d.IsApproximatelyEqual(f1.Point, f2.Point); protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer) => new PointFact(this.Point, this.Normal, organizer); public override MMTFact MakeMMTDeclaration() { SOMDoc tp = new OMS(MMTConstants.Point); return new MMTGeneralFact(Label, tp, Defines()); } public override SOMDoc Defines() => new OMA( new OMS(MMTConstants.Tuple), new[] { new OMLIT<float>(Point.x), new OMLIT<float>(Point.y), new OMLIT<float>(Point.z), } ); } /// <summary> /// A <see cref="PointFact"/> on a <see cref="AbstractLineFact"/> /// </summary> public class OnLineFact : FactWrappedCRTP<OnLineFact> { /// <summary> <see cref="PointFact"/>.<see cref="Fact.Id">Id</see> </summary> public string Pid; [JsonIgnore] public PointFact Point { get => (PointFact)FactRecorder.AllFacts[Pid]; } /// <summary> <see cref="AbstractLineFact"/>.<see cref="Fact.Id">Id</see> </summary> public string Rid; [JsonIgnore] public AbstractLineFact Ray { get => (AbstractLineFact)FactRecorder.AllFacts[Rid]; } /// <summary> \copydoc Fact.Fact </summary> public OnLineFact() : base() { this.Pid = null; this.Rid = null; } /// <summary> /// Standard Constructor: /// Initiates <see cref="Pid"/>, <see cref="Rid"/>, <see cref="Fact._URI"/> and creates MMT %Fact Server-Side /// </summary> /// <param name="pid">sets <see cref="Pid"/></param> /// <param name="rid">sets <see cref="Rid"/></param> /// <param name="organizer">sets <see cref="Fact._Facts"/></param> public OnLineFact(string pid, string rid, FactRecorder organizer) : base(organizer) { this.Pid = pid; this.Rid = rid; } protected override void RecalculateTransform() { Position = Point.Position; { //Rotation Vector3 up = Point.Rotation * Vector3.up; Vector3 forward = Ray.Dir; if (Math3d.IsApproximatelyEqual(up, forward)) { Vector3 arbitary = Math3d.IsApproximatelyEqual(forward, Vector3.forward) ? Vector3.right : Vector3.forward; up = Vector3.Cross(arbitary, forward); } Rotation = Quaternion.LookRotation(forward, up); } } /// <summary> /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_. /// </summary> /// <param name="pid">sets <see cref="Pid"/></param> /// <param name="rid">sets <see cref="Rid"/></param> /// <param name="uri">MMT URI</param> /// <param name="organizer">sets <see cref="Fact._Facts"/></param> public OnLineFact(string pid, string rid, SOMDoc _ServerDefinition, FactRecorder organizer) : base(organizer) { this.Pid = pid; this.Rid = rid; this.ServerDefinition = _ServerDefinition; _ = this.Label; } /// \copydoc Fact.parseFact(ScrollFact) public new static IEnumerator parseFact(List<Fact> ret, MMTFact fact) { string pointUri = ((OMS)((OMA)((OMA)((MMTGeneralFact)fact).type).arguments[0]).arguments[1]).uri; string lineUri = ((OMA)((OMA)((MMTGeneralFact)fact).type).arguments[0]).arguments[0] is OMS // standard case ? ((OMS)((OMA)((OMA)((MMTGeneralFact)fact).type).arguments[0]).arguments[0]).uri // case when line Uri has a projl on the line Argument : ((OMS)((OMA)((OMA)((OMA)((MMTGeneralFact)fact).type).arguments[0]).arguments[0]).arguments[0]).uri; if (!FactRecorder.AllFacts.ContainsKey(pointUri) || !FactRecorder.AllFacts.ContainsKey(lineUri)) yield break; ret.Add(new OnLineFact(pointUri, lineUri, fact.@ref, StageStatic.stage.factState)); } /// \copydoc Fact.generateLabel protected override string generateLabel() => Point.Label + "∈" + Ray.Label; /// \copydoc Fact.hasDependentFacts public override bool HasDependentFacts => true; /// \copydoc Fact.getDependentFactIds protected override string[] GetDependentFactIds() => new string[] { Pid, Rid }; protected override bool EquivalentWrapped(OnLineFact f1, OnLineFact f2) => DependentFactsEquivalent(f1, f2); protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer) => new OnLineFact(old_to_new[this.Pid], old_to_new[this.Rid], organizer); public override MMTFact MakeMMTDeclaration() { SOMDoc tp = new OMA( new OMS(MMTConstants.Ded), new[] { new OMA( new OMS(MMTConstants.OnLine), new[] { new OMS(Rid), new OMS(Pid) }),}); return new MMTGeneralFact(this.Label, tp, Defines()); } public override SOMDoc Defines() => null; } /// <summary> /// Two parallel Lines comprised of two <see cref="LineFact">LineFacts</see> /// </summary> public class ParallelLineFact : FactWrappedCRTP<ParallelLineFact> { /// @{ <summary> /// One <see cref="Fact.Id">Id</see> of two <see cref="LineFact"/> that are parallel [<see cref="Lid1"/>, <see cref="Lid2"/>]. /// </summary> public string Lid1, Lid2; /// @} [JsonIgnore] public AbstractLineFact Ray1 { get => (AbstractLineFact)FactRecorder.AllFacts[Lid1]; } [JsonIgnore] public AbstractLineFact Ray2 { get => (AbstractLineFact)FactRecorder.AllFacts[Lid2]; } /// <summary> \copydoc Fact.Fact </summary> public ParallelLineFact() : base() { this.Lid1 = null; this.Lid2 = null; } /// <summary> /// Standard Constructor /// </summary> /// <param name="lid1">sets <see cref="Lid1"/></param> /// <param name="lid2">sets <see cref="Lid2"/></param> /// <param name="organizer">sets <see cref="Fact._Facts"/></param> public ParallelLineFact(string lid1, string lid2, FactRecorder organizer) : base(organizer) { this.Lid1 = lid1; this.Lid2 = lid2; } protected override void RecalculateTransform() { } /// <summary> /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_. /// </summary> /// <param name="Lid1">sets <see cref="Lid1"/></param> /// <param name="Lid2">sets <see cref="Lid2"/></param> /// <param name="backendURI">MMT URI</param> /// <param name="organizer">sets <see cref="Fact._Facts"/></param> public ParallelLineFact(string Lid1, string Lid2, SOMDoc _ServerDefinition, FactRecorder organizer) : base(organizer) { this.Lid1 = Lid1; this.Lid2 = Lid2; this.ServerDefinition = _ServerDefinition; _ = this.Label; } /// \copydoc Fact.parseFact(ScrollFact) public new static IEnumerator parseFact(List<Fact> ret, MMTFact fact) { if (((MMTGeneralFact)fact).type is not OMA type) // proof DED yield break; OMA parallel_lines_OMA = (OMA)type.arguments[0]; // parallel string lineAUri = ((OMS)parallel_lines_OMA.arguments[0]).uri; string lineBUri = ((OMS)parallel_lines_OMA.arguments[1]).uri; if (!FactRecorder.AllFacts.ContainsKey(lineAUri) || !FactRecorder.AllFacts.ContainsKey(lineBUri)) yield break; ret.Add(new ParallelLineFact(lineAUri, lineBUri, fact.@ref, StageStatic.stage.factState)); } /// \copydoc Fact.generateLabel protected override string generateLabel() => Ray1.Label + "||" + Ray2.Label; public override MMTFact MakeMMTDeclaration() { SOMDoc tp = new OMA( new OMS(MMTConstants.Ded), new[] { new OMA( new OMS(MMTConstants.ParallelLine), new[] { new OMS(Lid1), new OMS(Lid2), } ), } ); return new MMTGeneralFact(this.Label, tp, Defines()); } public override SOMDoc Defines() => null; /// \copydoc Fact.hasDependentFacts public override bool HasDependentFacts => true; /// \copydoc Fact.getDependentFactIds protected override string[] GetDependentFactIds() => new string[] { Lid1, Lid2 }; /// \copydoc Fact.Equivalent(Fact, Fact) protected override bool EquivalentWrapped(ParallelLineFact f1, ParallelLineFact f2) => DependentFactsEquivalent(f1, f2); protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer) => new ParallelLineFact(old_to_new[this.Lid1], old_to_new[this.Lid2], organizer); } /// <summary> /// Used for BouncingScroll /// </summary> public class QuadFact : FactWrappedCRTP<QuadFact> { /// <summary> Defining Corners; Order is Cyclic; /// <see cref="PointFact"/>.<see cref="Fact.Id">Id</see> </summary> public string[] Pids; [JsonIgnore] public PointFact[] Points { get => _Points ??= Pids.Select(pid => (PointFact)FactRecorder.AllFacts[pid]).ToArray(); } private PointFact[] _Points; [JsonIgnore] public Vector3 Normal, Tangents, AltTangents; /// <summary> \copydoc Fact.Fact </summary> public QuadFact() : base() { } /// <summary> /// Standard Constructor: /// Initiates <see cref="Pids"/> and creates MMT %Fact Server-Side /// </summary> /// <param name="pid_corners">sets <see cref="Pids"/></param> /// <param name="organizer">sets <see cref="Fact._Facts"/></param> public QuadFact(string[] pid_corners, FactRecorder organizer) : base(organizer) { Init(pid_corners); } /// <summary> /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_. /// </summary> /// <param name="pid_corners">sets <see cref="Pids"/></param> /// <param name="uri">MMT URI</param> /// <param name="organizer">sets <see cref="Fact._Facts"/></param> public QuadFact(string[] pid_corners, SOMDoc _ServerDefinition, FactRecorder organizer) : base(organizer) { Init(pid_corners); this.ServerDefinition = _ServerDefinition; _ = this.Label; } private void Init(string[] pid_corners) { Pids = pid_corners; Tangents = (Points[0].Point - Points[1].Point).normalized; AltTangents = (Points[0].Point - Points[2].Point).normalized; Normal = Vector3.Cross(Tangents, AltTangents).normalized; if (Math3d.vectorPrecission < Math.Abs(Vector3.Dot(Normal, Points[0].Point - Points[3].Point))) throw new ArgumentException("All Points must lie on the same Plane!"); } /// \copydoc Fact.parseFact(ScrollFact) public new static IEnumerator parseFact(List<Fact> ret, MMTFact fact) { throw new NotImplementedException(); } public override MMTFact MakeMMTDeclaration() { SOMDoc tp = new OMS(MMTConstants.Wall); return new MMTGeneralFact(Label, tp, Defines()); } public override SOMDoc Defines() => new OMA( new OMS(MMTConstants.CreateWall), Pids.Select(pid => new OMS(pid)).ToArray() ); protected override bool EquivalentWrapped(QuadFact f1, QuadFact f2) { if (f1.Points.Length != f2.Points.Length) return false; int i = 0; for (; i < f2.Points.Length; i++) // 1st incedence if (f2.Points[i].Equivalent(f1.Points[0])) break; if (i == f2.Points.Length) // no match return false; for (int j = 1; j < f2.Points.Length; j++) // cyclic match if (!f2.Points[(i + j) % f2.Points.Length].Equivalent(f1.Points[j])) return false; return true; } public override bool HasDependentFacts => true; protected override string[] GetDependentFactIds() => Pids; protected override void RecalculateTransform() { } protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer) => new QuadFact(Pids.Select(pid => old_to_new[pid]).ToArray(), organizer); } /// <summary> /// Used for BouncingScroll /// </summary> public class TriangleFact : FactWrappedCRTP<TriangleFact> { /// <summary> Defining Verticies; Order gives NormalDirection; public Vector3[] Verticies; [JsonIgnore] public Vector3 Normal, Tangents, AltTangents; /// <summary> \copydoc Fact.Fact </summary> public TriangleFact() : base() { } /// <summary> /// Standard Constructor: /// Initiates <see cref="Pids"/> and creates MMT %Fact Server-Side /// </summary> /// <param name="pid_corners">sets <see cref="Pids"/></param> /// <param name="organizer">sets <see cref="Fact._Facts"/></param> public TriangleFact(Vector3[] Verticies, FactRecorder organizer) : base(organizer) { Init(Verticies); } /// <summary> /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_. /// </summary> /// <param name="pid_corners">sets <see cref="Pids"/></param> /// <param name="uri">MMT URI</param> /// <param name="organizer">sets <see cref="Fact._Facts"/></param> public TriangleFact(Vector3[] Verticies, SOMDoc _ServerDefinition, FactRecorder organizer) : base(organizer) { Init(Verticies); this.ServerDefinition = _ServerDefinition; _ = this.Label; } private void Init(Vector3[] Verticies) { this.Verticies = Verticies; Tangents = (Verticies[0] - Verticies[1]).normalized; AltTangents = (Verticies[0] - Verticies[2]).normalized; Normal = Vector3.Cross(Tangents, AltTangents).normalized; } /// \copydoc Fact.parseFact(ScrollFact) public new static IEnumerator parseFact(List<Fact> ret, MMTFact fact) { throw new NotImplementedException(); } public override MMTFact MakeMMTDeclaration() { SOMDoc tp = new OMS(MMTConstants.Triangle); return new MMTGeneralFact(Label, tp, Defines()); } public override SOMDoc Defines() => new OMA( new OMS(MMTConstants.CreateTriangle), Verticies.Select(vert => SOMDoc.MakeVector3(vert)).ToArray() ); protected override bool EquivalentWrapped(TriangleFact f1, TriangleFact f2) { int i = 0; for (; i < 3; i++) if (Math3d.IsApproximatelyEqual(f2.Verticies[i], f1.Verticies[0])) break; // 1st incedence return i < 3 // match ? then do: cyclic match && Math3d.IsApproximatelyEqual(f2.Verticies[(i + 1) % 3], f1.Verticies[1]) && Math3d.IsApproximatelyEqual(f2.Verticies[(i + 2) % 3], f1.Verticies[2]); } public override bool HasDependentFacts => false; protected override string[] GetDependentFactIds() => new string[0]; protected override void RecalculateTransform() { Position = Verticies[0]; Rotation = Quaternion.LookRotation(Tangents, Vector3.up); } protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer) => new TriangleFact(Verticies, organizer); }