/** This file is part of Shapes.
**
** Shapes is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** any later version.
**
** Shapes is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Shapes. If not, see .
**
** Copyright 2009, 2014, 2015 Henrik Tidefelt
**/
/** This examples shows how to compute the integral of argument variation for an open path, based on
** the kernel function that computes winding numbers for closed paths.
**/
##lookin ..Shapes
##lookin ..Shapes..Geometry
/** This function implements the integral of argument variation.
** It constructs a closed path by adding a counter-clockwise segment, gets its winding number, and compensates for the closing segment.
** The closing segment is computed as four straight line segments, at the biggest of the radii of the original path's endpoints.
**/
argumentVariation: \ pth origin →
[if pth.closed?
360° * [Geometry..winding pth origin]
{
pth0: [[shift ~origin] pth]
dStart: pth0.end.p
dEnd: pth0.begin.p
aStart: [angle dStart]
aEnd: { tmp: [angle dEnd]
[if tmp ≥ aStart tmp tmp+360°] }
aStep: (aEnd - aStart) / 4
d: [Numeric..Math..max [Numeric..Math..abs dStart] [Numeric..Math..abs dEnd]] * [normalized dStart]
360° * [Geometry..winding [[Data..range '1 '3].foldl \ p e → (p--[[rotate e*aStep] d]) pth0]--cycle (0m,0m)] - ( aEnd - aStart )
}]
/** Just for illustration, the path used to compute the winding number is extracted from the function body above.
**/
closedPath: \ pth origin →
{
dStart: pth.end.p - origin
dEnd: pth.begin.p - origin
aStart: [angle dStart]
aEnd: { tmp: [angle dEnd]
[if tmp ≥ aStart tmp tmp+360°] }
aStep: (aEnd - aStart) / 4
d: [Numeric..Math..max [Numeric..Math..abs dStart] [Numeric..Math..abs dEnd]] * [normalized dStart]
[[shift origin]
[[Data..range '1 '3].foldl \ p e → (p--[[rotate e*aStep] d]) [[shift ~origin] pth]]--cycle]
}
/** This helper function makes an illustration for a single path.
** It marks the origin, strokes the path, strokes the closed path for which the winding number is computed, and prints the argument variation near the origin.
**/
helper: \ pth →
( Graphics..newGroup
<< Traits..@stroking:Traits..RGB..RED | [Graphics..stroke [Geometry..circle 1mm]]
<< Traits..@dash:[Traits..dashpattern 2bp 2bp] | [Graphics..stroke [closedPath pth (0m,0m)]]
<< [Graphics..stroke pth head:[Graphics..ShapesArrow width:10 ...]]
<< [[shift (0cm,~1cm)] (Text..newText << [String..sprintf `%.1f°´ [argumentVariation pth (0m,0m)]/1°])])
/** All examples will be constructed as simple variations of this path.
**/
pth: (~1cm,~1cm)>(1%C^100°)--(1%C^)<(2cm,2cm)>(1%C^)--(1%C^)<(1cm,1cm)>(1%C^)--(1%C^)<(3cm,3cm)>(1%C^)--(1%C^45°)<(2cm,~2cm)
/** Finally, apply the helper on some paths.
**/
IO..•page << [helper pth]
<< [helper [Geometry..reverse pth]] >> [shift (7cm,0cm)]
<< [helper [[shift (~1.5cm,~1cm)] pth]] >> [shift (0cm,~7cm)]
<< [helper [Geometry..reverse [[shift (~1.5cm,~1cm)] pth]]] >> [shift (7cm,~7cm)]