Skip to content
Snippets Groups Projects
UnsortedFact.cs 18.16 KiB
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);
}