Skip to content
Snippets Groups Projects
AbstractLineFact.cs 13.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • using Newtonsoft.Json;
    using System.Collections.Generic;
    using TMPro;
    using UnityEngine;
    
    
    /// <summary>
    /// Base-class for 1D-Facts
    /// </summary>
    public abstract class AbstractLineFact : FactWrappedCRTP<AbstractLineFact>
    {
        /// @{ <summary>
        /// One <see cref="Fact.Id">Id</see> of two <see cref="PointFact"/> defining <see cref="Dir"/>.
        /// </summary>
        public string Pid1, Pid2;
        /// @}
    
    
        [JsonIgnore]
        public PointFact Point1 { get => (PointFact)_Facts[Pid1]; }
        [JsonIgnore]
        public PointFact Point2 { get => (PointFact)_Facts[Pid2]; }
    
    
    MaZiFAU's avatar
    MaZiFAU committed
        /// <summary> Distance between <see cref="AbstractLineFact.Pid1"/> and <see cref="AbstractLineFact.Pid2"/></summary>
        [JsonIgnore]
        public float Distance;
    
    
        /// <summary>
        /// Normalized Direction from <see cref="Pid1"/> to <see cref="Pid2"/>.
        /// </summary>
        public Vector3 Dir;
    
        /// <summary>
        /// \copydoc Fact.Fact()
        /// </summary>
        protected AbstractLineFact() : base()
        {
            Pid1 = null;
            Pid2 = null;
            Dir = Vector3.zero;
        }
    
        /// <summary>
        /// Copies <paramref name="fact"/> by initiating new MMT %Fact.
        /// </summary>
        /// <param name="fact">Fact to be copied</param>
        /// <param name="old_to_new"><c>Dictionary</c> mapping <paramref name="fact"/>.<see cref="getDependentFactIds"/> in <paramref name="fact"/>.<see cref="Fact._Facts"/> to corresponding <see cref="Fact.Id"/> in <paramref name="organizer"/> </param>
        /// <param name="organizer">sets <see cref="_Facts"/></param>
        protected AbstractLineFact(AbstractLineFact fact, Dictionary<string, string> old_to_new, FactOrganizer organizer) : base(fact, organizer)
        {
            set_public_members(old_to_new[fact.Pid1], old_to_new[fact.Pid2]);
        }
    
        /// <summary>
        /// Standard Constructor
        /// </summary>
        /// <param name="pid1">sets <see cref="AbstractLineFact.Pid1"/></param>
        /// <param name="pid2">sets <see cref="AbstractLineFact.Pid2"/></param>
        /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
        protected AbstractLineFact(string pid1, string pid2, FactOrganizer organizer) : base(organizer)
        {
            set_public_members(pid1, pid2);
        }
    
        /// <summary>
        /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
        /// </summary>
        /// <param name="pid1">sets <see cref="Pid1"/></param>
        /// <param name="pid2">sets <see cref="Pid2"/></param>
        /// <param name="backendURI">MMT URI</param>
        /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
        protected AbstractLineFact(string pid1, string pid2, string backendURI, FactOrganizer organizer) : base(organizer)
        {
            set_public_members(pid1, pid2);
            this._URI = backendURI;
        }
    
        /// <summary>
        /// Initiates <see cref="Pid1"/>, <see cref="Pid2"/>, <see cref="Dir"/>
        /// </summary>
        /// <param name="pid1">sets <see cref="Pid1"/></param>
        /// <param name="pid2">sets <see cref="Pid2"/></param>
        private void set_public_members(string pid1, string pid2)
        {
            this.Pid1 = pid1;
            this.Pid2 = pid2;
    
    MaZiFAU's avatar
    MaZiFAU committed
            this.Dir = (Point1.Point - Point2.Point).normalized;
            this.Distance = Dir.magnitude;
    
            Position = Vector3.Lerp(Point1.Point, Point2.Point, 0.5f);
            Rotation = Quaternion.LookRotation(Dir, Vector3.up);
            LocalScale.Set(Distance, 1, 1);
    
        }
    
        /// \copydoc Fact.hasDependentFacts
        public override bool hasDependentFacts()
        {
            return true;
        }
    
        /// \copydoc Fact.getDependentFactIds
        public override string[] getDependentFactIds()
        {
            return new string[] { Pid1, Pid2 };
        }
    
        /// \copydoc Fact.GetHashCode
        public override int GetHashCode()
        {
            return this.Pid1.GetHashCode() ^ this.Pid2.GetHashCode();
        }
    }
    
    /// <summary>
    /// Implements CRTP for <see cref="AbstractLineFact"/>; Escalates constructors;
    /// </summary>
    /// <typeparam name="T">class, which inherits from AbstractLineFactWrappedCRTP</typeparam>
    public abstract class AbstractLineFactWrappedCRTP<T> : AbstractLineFact where T : AbstractLineFactWrappedCRTP<T>
    {
        /// <summary>\copydoc Fact.Fact</summary>
        protected AbstractLineFactWrappedCRTP() : base() { }
    
        /// <summary>\copydoc AbstractLineFact.AbstractLineFact(AbstractLineFact, Dictionary{string, string}, FactOrganizer)</summary>
        protected AbstractLineFactWrappedCRTP(AbstractLineFactWrappedCRTP<T> fact, Dictionary<string, string> old_to_new, FactOrganizer organizer) : base(fact, old_to_new, organizer) { }
    
        /// <summary>\copydoc AbstractLineFact.AbstractLineFact(string, string, FactOrganizer)</summary>
        protected AbstractLineFactWrappedCRTP(string pid1, string pid2, FactOrganizer organizer) : base(pid1, pid2, organizer) { }
    
        /// <summary>\copydoc AbstractLineFact.AbstractLineFact(string, string, string, FactOrganizer)</summary>
        protected AbstractLineFactWrappedCRTP(string pid1, string pid2, string backendURI, FactOrganizer organizer) : base(pid1, pid2, backendURI, organizer) { }
    
        /// \copydoc Fact.Equivalent(Fact, Fact)
        protected override bool EquivalentWrapped(AbstractLineFact f1, AbstractLineFact f2)
            => EquivalentWrapped((T)f1, (T)f2);
    
        /// <summary>CRTP step of <see cref="EquivalentWrapped(AbstractLineFact, AbstractLineFact)"/></summary>
        protected abstract bool EquivalentWrapped(T f1, T f2);
    }
    
    /// <summary>
    /// Line within 3D Space of finite length
    /// </summary>
    public class LineFact : AbstractLineFactWrappedCRTP<LineFact>
    {
        /// \copydoc Fact.s_type
        [JsonProperty]
        protected static new string s_type = "LineFact";
    
        /// <summary> \copydoc Fact.Fact </summary>
    
    MaZiFAU's avatar
    MaZiFAU committed
        public LineFact() : base() { }
    
    
        /// <summary> \copydoc AbstractLineFact.AbstractLineFact(AbstractLineFact, Dictionary<string, string>, FactOrganizer) </summary>
        public LineFact(LineFact fact, Dictionary<string, string> old_to_new, FactOrganizer organizer) : base(fact, old_to_new, organizer)
            => init(old_to_new[fact.Pid1], old_to_new[fact.Pid2]);
    
        /// <summary> \copydoc AbstractLineFact.AbstractLineFact(string, string, string, FactOrganizer) </summary>
    
    MaZiFAU's avatar
    MaZiFAU committed
        public LineFact(string pid1, string pid2, string backendURI, FactOrganizer organizer) : base(pid1, pid2, backendURI, organizer) 
            => _ = this.Label;
    
    
        /// <summary> \copydoc AbstractLineFact.AbstractLineFact(string, string, FactOrganizer) </summary>
        public LineFact(string pid1, string pid2, FactOrganizer organizer) : base(pid1, pid2, organizer)
            => init(pid1, pid2);
    
        /// <summary>
        /// Initiates <see cref="AbstractLineFact.Pid1"/>, <see cref="AbstractLineFact.Pid2"/>, <see cref="Fact._URI"/> and creates MMT %Fact Server-Side
        /// </summary>
        /// <param name="pid1">sets <see cref="AbstractLineFact.Pid1"/></param>
        /// <param name="pid2">sets <see cref="AbstractLineFact.Pid2"/></param>
        private void init(string pid1, string pid2)
        {
    
                new OMA(
    
                        new OMS(pid1),
                        new OMS(pid2)
                    }
                );
    
    
            SOMDoc valueTp = new OMS(MMT_OMS_URI.RealLit);
    
    MaZiFAU's avatar
    MaZiFAU committed
            SOMDoc value = new OMF(Distance);
    
    
            MMTValueDeclaration mmtDecl = new(this.Label, lhs, valueTp, value);
            AddFactResponse.sendAdd(mmtDecl, out this._URI);
        }
    
        /// \copydoc Fact.parseFact(Scroll.ScrollFact)
        public new static LineFact parseFact(Scroll.ScrollFact fact)
        {
            string uri = fact.@ref.uri;
            string pointAUri = ((OMS)((OMA)((Scroll.ScrollValueFact)fact).lhs).arguments[0]).uri;
            string pointBUri = ((OMS)((OMA)((Scroll.ScrollValueFact)fact).lhs).arguments[1]).uri;
    
            if (StageStatic.stage.factState.ContainsKey(pointAUri)
             && StageStatic.stage.factState.ContainsKey(pointBUri))
                return new LineFact(pointAUri, pointBUri, uri, StageStatic.stage.factState);
    
            //If dependent facts do not exist return null
            else return null;
        }
    
        /// \copydoc Fact.generateLabel
        protected override string generateLabel()
            => "[" + _Facts[Pid1].Label + _Facts[Pid2].Label + "]";
    
        /// \copydoc Fact.instantiateDisplay(GameObject, Transform)
        public override GameObject instantiateDisplay(GameObject prefab, Transform transform)
        {
            var obj = GameObject.Instantiate(prefab, Vector3.zero, Quaternion.identity, transform);
            obj.transform.GetChild(0).gameObject.GetComponent<TextMeshProUGUI>().text = _Facts[this.Pid1].Label;
            obj.transform.GetChild(1).gameObject.GetComponent<TextMeshProUGUI>().text = _Facts[this.Pid2].Label;
            obj.GetComponent<FactWrapper>().fact = this;
            return obj;
        }
    
        /// \copydoc Fact.Equivalent(Fact, Fact)
        protected override bool EquivalentWrapped(LineFact f1, LineFact f2)
        {
            if ((f1.Pid1 == f2.Pid1 && f1.Pid2 == f2.Pid2))// || 
                //(f1.Pid1 == f2.Pid2 && f1.Pid2 == f2.Pid1))
                return true;
    
            PointFact p1f1 = (PointFact)_Facts[f1.Pid1];
            PointFact p2f1 = (PointFact)_Facts[f1.Pid2];
            PointFact p1f2 = (PointFact)_Facts[f2.Pid1];
            PointFact p2f2 = (PointFact)_Facts[f2.Pid2];
    
            return (p1f1.Equivalent(p1f2) && p2f1.Equivalent(p2f2))
                ;//|| (p1f1.Equivalent(p2f2) && p2f1.Equivalent(p1f2));
        }
    }
    
    /// <summary>
    /// Ray within 3D Space of infinite length
    /// </summary>
    public class RayFact : AbstractLineFactWrappedCRTP<RayFact>
    {
        /// \copydoc Fact.s_type
        [JsonProperty]
        protected static new string s_type = "RayFact";
    
        /// <summary> \copydoc Fact.Fact </summary>
        public RayFact() : base() { }
    
        /// <summary> \copydoc AbstractLineFact.AbstractLineFact(AbstractLineFact, Dictionary<string, string>, FactOrganizer) </summary>
        public RayFact(RayFact fact, Dictionary<string, string> old_to_new, FactOrganizer organizer) : base(fact, old_to_new, organizer)
            => init(old_to_new[fact.Pid1], old_to_new[fact.Pid2]);
    
        /// <summary> \copydoc AbstractLineFact.AbstractLineFact(string, string, string, FactOrganizer) </summary>
        public RayFact(string pid1, string pid2, string backendURI, FactOrganizer organizer) : base(pid1, pid2, backendURI, organizer)
            => _ = this.Label;
    
        /// <summary> \copydoc AbstractLineFact.AbstractLineFact(string, string, FactOrganizer) </summary>
        public RayFact(string pid1, string pid2, FactOrganizer organizer) : base(pid1, pid2, organizer)
            => init(pid1, pid2);
    
        /// <summary>
        /// Initiates <see cref="AbstractLineFact.Pid1"/>, <see cref="AbstractLineFact.Pid2"/>, <see cref="Fact._URI"/> and creates MMT %Fact Server-Side
        /// </summary>
        /// <param name="pid1">sets <see cref="AbstractLineFact.Pid1"/></param>
        /// <param name="pid2">sets <see cref="AbstractLineFact.Pid2"/></param>
        private void init(string pid1, string pid2)
        {
    
    MaZiFAU's avatar
    MaZiFAU committed
            LocalScale = new Vector3(float.PositiveInfinity, 1, 1);
    
    
            SOMDoc tp = new OMS(MMT_OMS_URI.LineType);
            SOMDoc df = new OMA(
                new OMS(MMT_OMS_URI.LineOf),
                new List<SOMDoc> {
    
                    new OMS(pid1),
                    new OMS(pid2)
                });
    
            AddFactResponse.sendAdd(new MMTSymbolDeclaration(this.Label, tp, df), out this._URI);
    
            ParsingDictionary.parseTermsToId[df.ToString()] = this._URI;
        }
    
        /// \copydoc Fact.parseFact(Scroll.ScrollFact)
        public new static RayFact parseFact(Scroll.ScrollFact fact)
        {
            string uri = fact.@ref.uri;
    
            if ((OMA)((Scroll.ScrollSymbolFact)fact).df == null)
                return null;
    
            string pointAUri = ((OMS)((OMA)((Scroll.ScrollSymbolFact)fact).df).arguments[0]).uri;
            string pointBUri = ((OMS)((OMA)((Scroll.ScrollSymbolFact)fact).df).arguments[1]).uri;
    
            if (StageStatic.stage.factState.ContainsKey(pointAUri)
                 && StageStatic.stage.factState.ContainsKey(pointBUri))
                return new RayFact(pointAUri, pointBUri, uri, StageStatic.stage.factState);
    
            //If dependent facts do not exist return null
            else return null;
        }
    
        /// \copydoc Fact.generateLabel
        protected override string generateLabel()
        {
            // TODO this string is too large to properly depict on scrolls. 
            // return "]" + _Facts[Pid1].Label + _Facts[Pid2].Label + "[";
            return _Facts[Pid1].Label + _Facts[Pid2].Label;
        }
    
        /// \copydoc Fact.instantiateDisplay(GameObject, Transform)
        public override GameObject instantiateDisplay(GameObject prefab, Transform transform)
        {
            var obj = GameObject.Instantiate(prefab, Vector3.zero, Quaternion.identity, transform);
            obj.transform.GetChild(0).gameObject.GetComponent<TextMeshProUGUI>().text = this.Label;
            obj.GetComponent<FactWrapper>().fact = this;
            return obj;
        }
    
        /// \copydoc Fact.Equivalent(Fact, Fact)
        protected override bool EquivalentWrapped(RayFact f1, RayFact f2)
        {
            if (!Math3d.IsApproximatelyParallel(f1.Dir, f2.Dir))
                return false;
    
            PointFact p1f1 = (PointFact)_Facts[f1.Pid1];
            PointFact p1f2 = (PointFact)_Facts[f2.Pid1];
            PointFact p2f2 = (PointFact)_Facts[f2.Pid2];
    
            return Math3d.IsPointApproximatelyOnLine(p1f1.Point, f1.Dir, p1f2.Point)
                && Math3d.IsPointApproximatelyOnLine(p1f1.Point, f1.Dir, p2f2.Point);
        }
    }