protected override TrTransform CalculateChildXf(List <PbKnot> parentKnots) { TrTransform actionInCanvasSpace; { PbKnot knot = GetAttachKnot(parentKnots); float rotationDegrees = knot.m_distance * App.UNITS_TO_METERS * m_twist; TrTransform offset = m_offset; // It's cleaner to tack a TrTransform.S(size) onto the action, but that // would modify .scale, which is currently interpreted as "pointer size" // (affecting control point density) and which is also assumed by most // brushes to be constant. if (m_pressureAffectsOffset) { offset.translation *= knot.m_pressuredSize; } else { offset.translation *= m_brush.BaseSize_LS; } TrTransform action = TrTransform.R(Quaternion.AngleAxis(rotationDegrees, Vector3.forward)) * offset; actionInCanvasSpace = action.TransformBy(knot.GetFrame(m_frame)); } var cur = parentKnots[parentKnots.Count - 1]; return(actionInCanvasSpace * cur.m_pointer); }
// // BaseBrushScript api // protected override bool UpdatePositionImpl( Vector3 translation, Quaternion rotation, float pressure) { TrTransform parentXf = TrTransform.TR(translation, rotation); // Update m_knots { Debug.Assert(m_knots.Count > 1, "There should always be at least 2 knots"); PbKnot cur = m_knots[m_knots.Count - 1]; PbKnot prev = m_knots[m_knots.Count - 2]; Vector3 move = parentXf.translation - prev.m_pointer.translation; cur.m_pointer = parentXf; float moveLen = move.magnitude; cur.m_tangentFrame = (moveLen > 1e-5f) ? MathUtils.ComputeMinimalRotationFrame( move / moveLen, prev.m_tangentFrame, cur.m_pointer.rotation) : prev.m_tangentFrame; cur.m_distance = prev.m_distance + moveLen; cur.m_pressuredSize = PressuredSize(pressure); } MaybeCreateChildren(); bool createdControlPoint = false; for (int i = 0; i < m_children.Count; ++i) { PbChild child = m_children[i]; var childXf = child.CalculateChildXfFixedScale(m_knots); if (child.m_brush.UpdatePosition_LS(childXf, pressure)) { // Need to save off any control point which is applicable to any of our children. // This does mean that if we have a giant tree of children, we might be saving // off every control point. // TODO: maybe there's a way for the parent to impose some order on this; // like it doesn't always send positions to its children? But that would make // interactive drawing less pretty. createdControlPoint = true; } } if (createdControlPoint) { m_knots.Add(m_knots[m_knots.Count - 1].Clone()); } return(createdControlPoint); }
// Looks through children to find ones that are attached to a knot. // Returns the distance to the most recent knot with a child. // If there are no such children, returns distance to the start of stroke. protected float DistanceSinceLastKnotBasedChild() { PbKnot cur = m_knots[m_knots.Count - 1]; float minDistance = cur.m_distance; foreach (var child_ in m_children) { var child = child_ as PbChildWithOffset; if (child != null) { float distanceFromChildToTip = cur.m_distance - child.GetAttachKnot(m_knots).m_distance; minDistance = Mathf.Min(minDistance, distanceFromChildToTip); } } return(minDistance); }
protected override TrTransform CalculateChildXf(List <PbKnot> parentKnots) { PbKnot lastKnot = parentKnots[parentKnots.Count - 1]; float distanceMeters = lastKnot.m_distance * App.UNITS_TO_METERS; float t = O.CyclesPerMeter * distanceMeters + (float)m_strand / O.NumStrands; // Our periodic function makes the plait look pretty square; maybe add // some rotation to break things up a bit? float rotations = (O.CyclesPerMeter * distanceMeters) * O.RotationsPerCycle; float amplitude = lastKnot.m_pressuredSize / 2; // /2 because size is diameter, not radius. TrTransform action = TrTransform.R(rotations * 360, Vector3.forward) * TrTransform.T(SomePeriodicFunction(t) * amplitude); TrTransform actionInCanvasSpace = action.TransformBy(lastKnot.GetFrame(AttachFrame.LineTangent)); return(actionInCanvasSpace * lastKnot.m_pointer); }