Skip to content
{{ message }}

Instantly share code, notes, and snippets.

# jbrennan/LineScaling.swift

Created Aug 3, 2016
The math behind a “drag to scale this line” operation.
 extension Line { /** Returns a scaled line according to the projection of `scalingPoint` onto the receiver. - parameter scalingPoint: A point interpreted as a vector used for scaling this line. This point should be something like the location of a touch or cursor during a "drag to scale" operation, but the point doesn't have to lie along the line itself. The point **must** be in the same coordinate space as the line. */ func lineByScalingToTouchPoint(scalingPoint: Point) -> Line { // This algorithm works by // - treating the incoming point as a vector, // - treating the line (self) as a vector along an infinite line // - offsetting both vectors by the start point of the line // - so the line has 0 as its origin to make math easier // - projecting the point vector onto the line // - finally offseting the projected vector BACK by the start amount of the line. // Projecting onto self is like casting a shadow of the scaling point onto our line. // That shadow is our scaled line. // Subtract the start from the end of the line and scaling point, so the line has a 0 origin. let lineVector = end - start let scalingPointOffsetByStart = scalingPoint - start // Projection(scalingVector) = constant * lineVector = ((scalingVector dot-product lineVector) / (lineVec dot-product itself)) * lineVec let vectorScalingConstantNumerator = scalingPointOffsetByStart.dotProduct(lineVector) let vectorScalingConstantDenomenator = lineVector.dotProduct(lineVector) let vectorScalingConstant = vectorScalingConstantNumerator / vectorScalingConstantDenomenator // see https://www.youtube.com/watch?v=27vT-NWuw0M let projectionVector = vectorScalingConstant * lineVector return Line(start: start, end: projectionVector + start) } }
to join this conversation on GitHub. Already have an account? Sign in to comment