public override object AddAttachment(TransformFollower attach, bool normalized = false) { if (normalized) return AddAttachmentNormalized(attach); else return AddAttachmentNotNormalized(attach); }
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 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); }
public override object AddAttachment(TransformFollower attach, bool normalized = false) { if (normalized) { return(AddAttachmentNormalized(attach)); } else { return(AddAttachmentNotNormalized(attach)); } }
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); } }
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)); }
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); }
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); }
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"); }
public override object AddAttachment(TransformFollower attach, bool normalized) { return(normalized ? AddAttachmentNormalized(attach) : AddAttachmentNotNormalized(attach)); }
public override object AddAttachment(TransformFollower attach, bool normalized) { return normalized ? AddAttachmentNormalized(attach) : AddAttachmentNotNormalized(attach); }
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; }
/// <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);