public override object AddAttachment(TransformFollower attach, bool normalized = false)
 {
     if (normalized)
         return AddAttachmentNormalized(attach);
     else
         return AddAttachmentNotNormalized(attach);
 }
Example #2
0
        private PartAttachment AddPartAttachment(Vector3 position, TransformFollower.Transformable target, bool normalized = false)
        {
            TransformFollower follower = TransformFollower.createFollower(partModel, position, target);
            object            data     = shape.AddAttachment(follower, normalized);

            return(new PartAttachment(follower, data));
        }
Example #3
0
        private void InitializeNode(AttachNode node)
        {
            Vector3 position = transform.TransformPoint(node.position);

            TransformFollower follower = TransformFollower.createFollower(partModel, position, new NodeTransformable(part, node));

            // When the object is symmetryClone, the nodes will be already in offset, not in standard offset.
            object data = shape.AddAttachment(follower, !symmetryClone);

            nodeAttachments.Add(data);
        }
Example #4
0
 public override object AddAttachment(TransformFollower attach, bool normalized = false)
 {
     if (normalized)
     {
         return(AddAttachmentNormalized(attach));
     }
     else
     {
         return(AddAttachmentNotNormalized(attach));
     }
 }
Example #5
0
        public static TransformFollower createFollower(Transform parent, Vector3 position, Transformable target)
        {
            GameObject        go  = new GameObject("Follower:" + target.ToString(), typeof(TransformFollower));
            TransformFollower loc = go.GetComponent <TransformFollower>();

            loc.target = target;

            go.transform.position = position;
            loc.SetParentInternal(parent);

            return(loc);
        }
        private void UpdateShape()
        {
            if (shapeName == oldShapeName)
            {
                return;
            }

            ProceduralAbstractShape newShape;

            if (!availableShapes.TryGetValue(shapeName, out newShape))
            {
                Debug.LogError("*ST* Unable to find compShape: " + shapeName);
                shapeName = oldShapeName;
                return;
            }

            if (shape != null)
            {
                shape.isEnabled = shape.enabled = false;

                // Pull off all the attachments, resetting them to standard offset, then reattach in the new shape.
                for (int i = 0; i < nodeAttachments.Count; ++i)
                {
                    TransformFollower follower = shape.RemoveAttachment(nodeAttachments[i], true);
                    nodeAttachments[i] = newShape.AddAttachment(follower, true);
                }
                if (parentAttachment != null)
                {
                    shape.RemoveAttachment(parentAttachment.data, true);
                    parentAttachment.data = newShape.AddAttachment(parentAttachment.follower, true);
                }
                foreach (PartAttachment childAttachment in childAttachments)
                {
                    shape.RemoveAttachment(childAttachment.data, true);
                    childAttachment.data = newShape.AddAttachment(childAttachment.follower, true);
                }
                foreach (ModelAttachment attach in attachments)
                {
                    TransformFollower follower = shape.RemoveAttachment(attach.data, true);
                    attach.data = newShape.AddAttachment(follower, true);
                }
            }

            shape           = newShape;
            shape.isEnabled = shape.enabled = true;

            oldShapeName = shapeName;

            if (HighLogic.LoadedSceneIsEditor)
            {
                GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship);
            }
        }
Example #7
0
        public void AddAttachment(Transform child, Vector3 offset, bool normalized)
        {
            ModelAttachment attach = new ModelAttachment();

            attach.child = child;
            Vector3 position = child.TransformPoint(offset);

            TransformFollower follower = TransformFollower.createFollower(partModel, position, new TransformFollower.TransformTransformable(child, position, Space.World));

            attach.data = shape.AddAttachment(follower, normalized);

            attachments.AddLast(attach);
        }
        private PartAttachment AddPartAttachment(Vector3 position, TransformFollower.Transformable target, bool normalized = false)
        {
            if ((object)target == null)
            {
                Debug.Log("AddPartAttachment: null target!");
            }
            TransformFollower follower = TransformFollower.CreateFollower(partModel, position, target);

            if ((object)follower == null)
            {
                Debug.Log("AddPartAttachment: null follower!");
            }
            object data = shape.AddAttachment(follower, normalized);

            return(new PartAttachment(follower, data));
        }
Example #9
0
        private object AddAttachmentNormalized(TransformFollower attach)
        {
            Attachment ret = new Attachment
            {
                follower = attach
            };

            Vector3 position = attach.transform.localPosition;

            // This is easy, just get the UV and location correctly and force an update.
            // as the position might be after some rotation and translation, it might not be exactly +/- 0.5
            if (Mathf.Abs(Mathf.Abs(position.y) - 0.5f) < 1e-5f)
            {
                if (position.y > 0)
                {
                    ret.location = Location.Top;
                    ret.uv       = new Vector2(position.x + 0.5f, position.z + 0.5f);
                    ret.node     = topAttachments.AddLast(ret);
                    ret.follower.SetLocalRotationReference(Quaternion.LookRotation(Vector3.up, Vector3.right));
                }
                else if (position.y < 0)
                {
                    ret.location = Location.Bottom;
                    ret.uv       = new Vector2(position.x + 0.5f, position.z + 0.5f);
                    ret.node     = bottomAttachments.AddLast(ret);
                    ret.follower.SetLocalRotationReference(Quaternion.LookRotation(Vector3.down, Vector3.left));
                }
            }
            else
            {
                ret.location = Location.Side;
                float theta = Mathf.Atan2(-position.z, position.x);
                ret.uv[0] = (Mathf.InverseLerp(-Mathf.PI, Mathf.PI, theta) + 0.5f) % 1.0f;
                ret.uv[1] = 0.5f - position.y;

                Vector3 normal = new Vector3(position.x * 2f, 0, position.z * 2f);
                ret.follower.SetLocalRotationReference(Quaternion.FromToRotation(Vector3.up, normal));

                // side attachments are kept sorted
                AddSideAttachment(ret);
            }
            ForceNextUpdate();

            //Debug.LogWarning("Adding normalized attachment to position=" + position + " location=" + ret.location + " uv=" + ret.uv + " attach=" + attach.name);
            return(ret);
        }
Example #10
0
        public void RemoveAttachment(Transform child)
        {
            LinkedListNode <ModelAttachment> node;

            for (node = attachments.First; node != null; node = node.Next)
            {
                if (node.Value.child == child)
                {
                    goto foundNode;
                }
            }
            // Not found, fail silently
            return;

foundNode:
            TransformFollower follower = shape.RemoveAttachment(node.Value.data);

            Destroy(follower);

            attachments.Remove(node);
        }
 public PartAttachment(TransformFollower follower, object data)
 {
     this.follower = follower;
     this.data = data;
 }
        private PartAttachment AddPartAttachment(Vector3 position, TransformFollower.Transformable target, bool normalized = false)
        {
            if ((object)target == null)
                Debug.Log("AddPartAttachment: null target!");
            TransformFollower follower = TransformFollower.CreateFollower(partModel, position, target);
            if((object)follower == null)
                Debug.Log("AddPartAttachment: null follower!");
            object data = shape.AddAttachment(follower, normalized);

            return new PartAttachment(follower, data);
        }
Example #13
0
        private object AddAttachmentNotNormalized(TransformFollower attach)
        {
            Attachment ret = new Attachment
            {
                follower = attach
            };

            if (lastProfile == null)
            {
                throw new InvalidOperationException("Can't child non-normalized attachments prior to the first update");
            }

            // All the code from here down assumes the part is a convex shape, which is fair as it needs to be convex for
            // partCollider purposes anyhow. If we allow concave shapes it will need some refinement.
            Vector3 position = attach.transform.localPosition;

            // Convert the offset into spherical coords
            float r = position.magnitude;
            float theta, phi;

            if (r > 0f)
            {
                theta = Mathf.Atan2(-position.z, position.x);
                phi   = Mathf.Asin(position.y / r);
            }
            else
            {
                // move the origin to the top to avoid divide by zeros.
                theta = 0;
                phi   = Mathf.PI / 2f;
            }


            // top or bottom?
            // ReSharper disable once CompareOfFloatsByEqualityOperator
            if (phi != 0)
            {
                ProfilePoint topBot = (phi < 0) ? lastProfile.First.Value : lastProfile.Last.Value;

                float tbR   = Mathf.Sqrt(topBot.y * topBot.y + topBot.dia * topBot.dia * 0.25f);
                float tbPhi = Mathf.Asin(topBot.y / tbR);

                if (Mathf.Abs(phi) >= Mathf.Abs(tbPhi))
                {
                    ret.uv = topBot.dia < 0.001f ?
                             new Vector2(0.5f, 0.5f) :
                             new Vector2(position.x / topBot.dia * 2f + 0.5f, position.z / topBot.dia * 2f + 0.5f);

                    if (phi > 0)
                    {
                        ret.location = Location.Top;
                        ret.node     = topAttachments.AddLast(ret);
                        ret.follower.SetLocalRotationReference(Quaternion.LookRotation(Vector3.up, Vector3.right));
                    }
                    else
                    {
                        ret.location = Location.Bottom;
                        ret.node     = bottomAttachments.AddLast(ret);
                        ret.follower.SetLocalRotationReference(Quaternion.LookRotation(Vector3.down, Vector3.left));
                    }
                    //Debug.LogWarning("Adding non-normalized attachment to position=" + position + " location=" + ret.location + " uv=" + ret.uv + " attach=" + attach.name);
                    return(ret);
                }
            }

            // THis is the slope of a line projecting out towards our attachment
            float s = position.y / Mathf.Sqrt(position.x * position.x + position.z * position.z);

            ret.location = Location.Side;
            ret.uv[0]    = (Mathf.InverseLerp(-Mathf.PI, Mathf.PI, theta) + 0.5f) % 1.0f;

            ProfilePoint pt = lastProfile.First.Value;

            for (LinkedListNode <ProfilePoint> ptNode = lastProfile.First.Next; ptNode != null; ptNode = ptNode.Next)
            {
                if (!ptNode.Value.inCollider)
                {
                    continue;
                }
                ProfilePoint pv = pt;
                pt = ptNode.Value;

                float ptR   = Mathf.Sqrt(pt.y * pt.y + pt.dia * pt.dia * 0.25f);
                float ptPhi = Mathf.Asin(pt.y / ptR);

                //Debug.LogWarning("ptPhi=" + ptPhi + " phi=" + phi);

                if (phi > ptPhi)
                {
                    continue;
                }

                // so we know the attachment is somewhere between the previous and this circle
                // Geometry: draw a line between the point (dia/2, y) in the prev circle and  (dia/2, y) in the current circle (parametric in t)
                // find the point on the line where y = s * dia / 2  and solve for t

                // r(t) = r0 + (r1-r0)t
                // y(t) = y0 + (y1-y0)t
                // y(t) = s * r(t)
                //
                // y0 + (y1-y0)t = s r0 + s (r1-r0) t
                // ((y1-y0)- s(r1-r0))t = s r0 - y0
                // t = (s r0 - y0) / ((y1-y0) - s(r1-r0))

                float r0 = pv.dia * 0.5f;
                float r1 = pt.dia * 0.5f;

                float t = (s * r0 - pv.y) / ((pt.y - pv.y) - s * (r1 - r0));

                //Debug.LogWarning(string.Format("New Attachment: pv=({0:F2}, {1:F2}) pt=({2:F2}, {3:F2}) s={4:F2} t={5:F2}", r0, pv.y, r1, pt.y, s, t));

                ret.uv[1] = Mathf.Lerp(pv.v, pt.v, t);
                if (ret.uv[1] > 1.0f)
                {
                    Debug.LogError("result off end of segment v=" + ret.uv[1] + " pv.v=" + pv.v + " pt.v=" + pt.v + " t=" + t);
                }

                //
                Vector3    normal;
                Quaternion rot = SideAttachOrientation(pv, pt, theta, out normal);
                ret.follower.SetLocalRotationReference(rot);

                AddSideAttachment(ret);
                //Debug.LogWarning("Adding non-normalized attachment to position=" + position + " location=" + ret.location + " uv=" + ret.uv + " attach=" + attach.name);
                return(ret);
            }

            // This should be impossible to reach
            throw new InvalidProgramException("Unreachable code reached");
        }
Example #14
0
 public override object AddAttachment(TransformFollower attach, bool normalized)
 {
     return(normalized ? AddAttachmentNormalized(attach) : AddAttachmentNotNormalized(attach));
 }
Example #15
0
 public PartAttachment(TransformFollower follower, object data)
 {
     this.follower = follower;
     this.data     = data;
 }
 public override object AddAttachment(TransformFollower attach, bool normalized)
 {
     return normalized ? AddAttachmentNormalized(attach) : AddAttachmentNotNormalized(attach);
 }
Example #17
0
        private PartAttachment AddPartAttachment(Vector3 position, TransformFollower.Transformable target, bool normalized = false)
        {
            TransformFollower follower = TransformFollower.createFollower(partModel, position, target);
            object data = shape.AddAttachment(follower, normalized);

            return new PartAttachment(follower, data);
        }
        private object AddAttachmentNotNormalized(TransformFollower attach)
        {
            Attachment ret = new Attachment();
            ret.follower = attach;

            if (lastProfile == null)
                throw new InvalidOperationException("Can't child non-normalized attachments prior to the first update");

            // All the code from here down assumes the part is a convex shape, which is fair as it needs to be convex for
            // partCollider purposes anyhow. If we allow concave shapes it will need some refinement.
            Vector3 position = attach.transform.localPosition;

            // Convert the offset into spherical coords
            float r = position.magnitude;
            float theta, phi;
            if (r > 0f)
            {
                theta = Mathf.Atan2(-position.z, position.x);
                phi = Mathf.Asin(position.y / r);
            }
            else
            {
                // move the origin to the top to avoid divide by zeros.
                r = 0.1f;
                theta = 0;
                phi = Mathf.PI / 2f;
            }

            // pt or bottom?
            if (phi != 0)
            {
                ProfilePoint topBot = (phi < 0) ? lastProfile.First.Value : lastProfile.Last.Value;

                float tbR = Mathf.Sqrt(topBot.y * topBot.y + topBot.dia * topBot.dia * 0.25f);
                float tbPhi = Mathf.Asin(topBot.y / tbR);

                if (Mathf.Abs(phi) >= Mathf.Abs(tbPhi))
                {
                    if (topBot.dia < 0.001f)
                        ret.uv = new Vector2(0.5f, 0.5f);
                    else
                        ret.uv = new Vector2(position.x / topBot.dia * 2f + 0.5f, position.z / topBot.dia * 2f + 0.5f);
                    if (phi > 0)
                    {
                        ret.location = Location.Top;
                        ret.node = topAttachments.AddLast(ret);
                        ret.follower.SetLocalRotationReference(Quaternion.LookRotation(Vector3.up, Vector3.right));
                    }
                    else
                    {
                        ret.location = Location.Bottom;
                        ret.node = bottomAttachments.AddLast(ret);
                        ret.follower.SetLocalRotationReference(Quaternion.LookRotation(Vector3.down, Vector3.left));
                    }
                    //Debug.LogWarning("Adding non-normalized attachment to position=" + position + " location=" + ret.location + " uv=" + ret.uv + " attach=" + attach.name);
                    return ret;
                }
            }

            // THis is the slope of a line projecting out towards our attachment
            float s = position.y / Mathf.Sqrt(position.x * position.x + position.z * position.z);

            ret.location = Location.Side;
            ret.uv[0] = (Mathf.InverseLerp(-Mathf.PI, Mathf.PI, theta) + 0.5f) % 1.0f;

            ProfilePoint pv = null;
            ProfilePoint pt = lastProfile.First.Value;
            for (LinkedListNode<ProfilePoint> ptNode = lastProfile.First.Next; ptNode != null; ptNode = ptNode.Next)
            {
                if (!ptNode.Value.inCollider)
                    continue;
                pv = pt;
                pt = ptNode.Value;

                float ptR = Mathf.Sqrt(pt.y * pt.y + pt.dia * pt.dia * 0.25f);
                float ptPhi = Mathf.Asin(pt.y / ptR);

                //Debug.LogWarning("ptPhi=" + ptPhi + " phi=" + phi);

                if (phi > ptPhi)
                    continue;

                // so we know the attachment is somewhere between the previous and this circle
                // Geometry: draw a line between the point (dia/2, y) in the prev circle and  (dia/2, y) in the current circle (parametric in t)
                // find the point on the line where y = s * dia / 2  and solve for t

                // r(t) = r0 + (r1-r0)t
                // y(t) = y0 + (y1-y0)t
                // y(t) = s * r(t)
                //
                // y0 + (y1-y0)t = s r0 + s (r1-r0) t
                // ((y1-y0)- s(r1-r0))t = s r0 - y0
                // t = (s r0 - y0) / ((y1-y0) - s(r1-r0))

                float r0 = pv.dia * 0.5f;
                float r1 = pt.dia * 0.5f;

                float t = (s * r0 - pv.y) / ((pt.y - pv.y) - s * (r1 - r0));

                //Debug.LogWarning(string.Format("New Attachment: pv=({0:F2}, {1:F2}) pt=({2:F2}, {3:F2}) s={4:F2} t={5:F2}", r0, pv.y, r1, pt.y, s, t));

                ret.uv[1] = Mathf.Lerp(pv.v, pt.v, t);
                if (ret.uv[1] > 1.0f)
                    Debug.LogError("result off end of segment v=" + ret.uv[1] + " pv.v=" + pv.v + " pt.v=" + pt.v + " t=" + t);

                //
                Vector3 normal;
                Quaternion rot = SideAttachOrientation(pv, pt, theta, out normal);
                ret.follower.SetLocalRotationReference(rot);

                AddSideAttachment(ret);
                //Debug.LogWarning("Adding non-normalized attachment to position=" + position + " location=" + ret.location + " uv=" + ret.uv + " attach=" + attach.name);
                return ret;
            }

            // This should be impossible to reach
            throw new InvalidProgramException("Unreachable code reached");
        }
        private object AddAttachmentNormalized(TransformFollower attach)
        {
            Attachment ret = new Attachment();
            ret.follower = attach;

            Vector3 position = attach.transform.localPosition;

            // This is easy, just get the UV and location correctly and force an update.
            // as the position might be after some rotation and translation, it might not be exactly +/- 0.5
            if (Mathf.Abs(Mathf.Abs(position.y) - 0.5f) < 1e-5f)
            {
                if (position.y > 0)
                {
                    ret.location = Location.Top;
                    ret.uv = new Vector2(position.x + 0.5f, position.z + 0.5f);
                    ret.node = topAttachments.AddLast(ret);
                    ret.follower.SetLocalRotationReference(Quaternion.LookRotation(Vector3.up, Vector3.right));
                }
                else if (position.y < 0)
                {
                    ret.location = Location.Bottom;
                    ret.uv = new Vector2(position.x + 0.5f, position.z + 0.5f);
                    ret.node = bottomAttachments.AddLast(ret);
                    ret.follower.SetLocalRotationReference(Quaternion.LookRotation(Vector3.down, Vector3.left));
                }
            }
            else
            {
                ret.location = Location.Side;
                float theta = Mathf.Atan2(-position.z, position.x);
                ret.uv[0] = (Mathf.InverseLerp(-Mathf.PI, Mathf.PI, theta) + 0.5f) % 1.0f;
                ret.uv[1] = 0.5f - position.y;

                Vector3 normal = new Vector3(position.x * 2f, 0, position.z * 2f);
                ret.follower.SetLocalRotationReference(Quaternion.FromToRotation(Vector3.up, normal));

                // side attachments are kept sorted
                AddSideAttachment(ret);
            }
            ForceNextUpdate();

            //Debug.LogWarning("Adding normalized attachment to position=" + position + " location=" + ret.location + " uv=" + ret.uv + " attach=" + attach.name);
            return ret;
        }
Example #20
0
 /// <summary>
 /// Add object attached to the surface of this part.
 /// Base classes should proportionally move the location and orientation (rotation) as the part stretches.
 /// The return value will be passed back to removeTankAttachment when i's detached
 /// </summary>
 /// <param name="child">Transform offset follower for the attachment</param>
 /// <param name="normalized">If true, the current offset of the attachment is in 'normalized' offset
 /// - where i would be in space on a unit length and diameter cylinder. This method will relocate the object.</param>
 /// <returns>Object used to track the attachment for Remove method</returns>
 public abstract object AddAttachment(TransformFollower attach, bool normalized = false);
 /// <summary>
 /// Add object attached to the surface of this part.
 /// Base classes should proportionally move the location and orientation (rotation) as the part stretches.
 /// The return value will be passed back to removeTankAttachment when i's detached
 /// </summary>
 /// <param name="attach">Transform offset follower for the attachment</param>
 /// <param name="normalized">If true, the current offset of the attachment is in 'normalized' offset
 /// - where i would be in space on a unit length and diameter cylinder. This method will relocate the object.</param>
 /// <returns>Object used to track the attachment for Remove method</returns>
 public abstract object AddAttachment(TransformFollower attach, bool normalized);