Created
September 7, 2021 13:56
-
-
Save XerxesZorgon/3563a355c5f61469ceddd69000ae88cc to your computer and use it in GitHub Desktop.
Converts curves in BezStruct to svg format.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% Converts curves in BezStruct to svg format. | |
% | |
% | |
% Input(s) | |
% BezStruct: | |
% BezCurves: Structure of Bezier curves for each of the 6 fundamental curves | |
% Sheer, Freeboard, Profile, A (homotopy), eta1 and eta2 | |
% sections: Section curves derived from the Bezier functions at nSections | |
% intervals along the hull | |
% functions: Symbolically defined functions for each section (eta), and a | |
% final set for the transom, (trans_x, trans_y, trans_z) | |
% Boat parameters: | |
% LOA: Length overall | |
% Beam: Maximum beam | |
% Draft: Maximum draft | |
% Midship: Distance from bow of maximum beam | |
% | |
% svgDir: Directory containing output svg files for each curve | |
% | |
% | |
% Output(s) | |
% Bow/stern and section curves saved to separate files in svgDir | |
% | |
% Example: | |
% BezStruct = BezierHull(<curves.xlsx>); | |
% bez2svg(BezStruct,svgDir); | |
% | |
% See also: BezierHull, idNestObjects | |
% | |
% | |
% Dependencies: func2Coords, pts2svg, funcSolve, disperse | |
% | |
% | |
% Written by: John Peach 06-Sep-2021 | |
% Wild Peaches | |
% | |
% Revisions: | |
function bez2svg(BezStruct,svgDir) | |
% Distance between sections, number of sections | |
dSect = 0.5; | |
LOA = BezStruct.LOA; | |
xt = dSect:dSect:LOA-dSect; | |
nSects = numel(xt); | |
ft2in = 12; | |
% Sheer, freeboard and profile at each section | |
t = linspace(0,1,50); | |
BZ.s = BezStruct.symFuncs.s; | |
BZ.f = BezStruct.symFuncs.f; | |
BZ.p = BezStruct.symFuncs.p; | |
BZ.A = BezStruct.symFuncs.A; | |
BZ.eta1 = BezStruct.symFuncs.eta1; | |
BZ.eta2 = BezStruct.symFuncs.eta2; | |
BZ.LOA = LOA; | |
%% Bow sheer | |
Pts = func2Coords(BZ.s,[LOA-dSect,LOA],LOA,50); | |
bowPts = ft2in * [Pts; [Pts(1,1) Pts(end,2)]; Pts(1,:)]; | |
% Write points to svg format | |
pts2svg(bowPts,'bowSheer',svgDir); | |
%% Stern sheer | |
Pts = func2Coords(BZ.s,[0,dSect],LOA,100); | |
sternPts = ft2in * [Pts; [Pts(end,1),0]; Pts(1,:)]; | |
pts2svg(sternPts,'sternSheer',svgDir); | |
%% Combined freeboard/profile at bow and stern | |
fPts = func2Coords(BZ.f,[LOA-dSect,LOA],LOA,50); | |
pPts = func2Coords(BZ.p,[LOA-dSect,LOA],LOA,50); | |
bowPts = ft2in * [fPts; flipud(pPts); fPts(1,:)]; | |
pts2svg(bowPts,'bowFbdProf',svgDir); | |
fPts = func2Coords(BZ.f,[0,dSect],LOA,50); | |
pPts = func2Coords(BZ.p,[0,dSect],LOA,50); | |
sternPts = ft2in * [fPts;flipud(pPts);fPts(1,:)]; | |
pts2svg(sternPts,'sternFbdProf',svgDir); | |
%% Sections | |
for k = 1:nSects | |
rtPts = section_at_x(xt(k),BZ,50); | |
ltPts = flipud([-rtPts(:,1) rtPts(:,2)]); | |
section = ft2in * [rtPts; ltPts; rtPts(1,:)]; | |
secFName = ['Section_',num2str(xt(k))]; | |
pts2svg(section,secFName,svgDir); | |
endfor | |
endfunction | |
function Pts = func2Coords(func,Rng,LOA,nPts) | |
% Locations on x-axis in Rng | |
x = linspace(min(Rng),max(Rng),nPts); | |
% Values of parameter t generating x | |
t = funcSolve(func.x,x)'; | |
% Coordinates | |
Pts = [func.x(t) func.y(t)]; | |
endfunction | |
function Pts = section_at_x(x,BZ,nPts) | |
% Parameter t for each function | |
st = funcSolve(BZ.s.x,x); | |
ft = funcSolve(BZ.f.x,x); | |
pt = funcSolve(BZ.p.x,x); | |
At = funcSolve(BZ.A.x,x); | |
% Evaluate s,f,t,A at x | |
sx = BZ.s.y(st); | |
fx = BZ.f.y(ft); | |
px = BZ.p.y(pt); | |
Ax = BZ.A.y(At); | |
% Section curves in y,z coordinates | |
y = @(t) sx * ((1-Ax) * BZ.eta1.x(t) + Ax * BZ.eta2.x(t)); | |
z = @(t) (fx-px) * ((1-Ax) * BZ.eta1.y(t) + Ax * BZ.eta2.y(t)) + px; | |
t = linspace(0,1,nPts)'; | |
Pts = [y(t) z(t)]; | |
endfunction | |
function t = funcSolve(f,y) | |
% Returns t such that f(t) = y for input values of y | |
% | |
% | |
% Input(s) | |
% f: Function handle | |
% y: Values where f(t) are required | |
% | |
% Output(s) | |
% t: Values such that f(t) = y | |
% Number of data points | |
n = numel(y); | |
% Initialize output vector | |
t = nan(1,n); | |
% Loop over each y_k to find t_k | |
for k = 1:n | |
try | |
s = fminbnd(@(x) (f(x) - y(k)).^2,0,1); | |
t(k) = s; | |
catch | |
end_try_catch | |
endfor | |
% Remove values of t outside [0,1] | |
t(t < 0) = nan; | |
t(t > 1) = nan; | |
endfunction | |
function pts2svg(pts,curveName,svgDir) | |
% Open file | |
svgFile = fullfile(svgDir,[curveName '.svg']); | |
fid = fopen(svgFile,'w'); | |
% Dimensions of the curve | |
pts = pts - min(pts) + [0.1 0.1]; % Shift to align with x,y axes + 0.1 units | |
[x,y] = disperse(roundi(max(pts),5,'up')); | |
% Write header lines | |
fprintf(fid,'<?xml version="1.0" standalone="no"?>\n'); | |
fprintf(fid,'<svg width="%5.2fin" height="%5.2in" viewBox="0 0 %d %d" xmlns="http://www.w3.org/2000/svg" version="1.1">\n',x,y,x,y); | |
fprintf(fid,'<title> End curve or section: %s </title>\n',curveName); | |
fprintf(fid,'<desc>A path that draws a curve</desc>\n'); | |
% Write points to svg files | |
fprintf(fid,'<path d="M %5.2f %5.2f\n',pts(1,1),pts(1,2)); | |
for k = 2:size(pts,1) | |
fprintf(fid,' L %5.2f %5.2f\n',pts(k,1),pts(k,2)); | |
endfor | |
fprintf(fid,' z"\n'); | |
fprintf(fid,' fill="none" stroke="blue" stroke-width="1" />\n'); | |
fprintf(fid,'</svg>\n'); | |
% Close file | |
fclose(fid); | |
endfunction | |
% DISPERSE was created so that you can stop doing things like this: | |
% | |
% x1 = array(1); % ...repetitive assignments from an array | |
% x2 = array(2); | |
% x3 = array(3); | |
% x4 = array(4); | |
% | |
% and start doing things like this: | |
% | |
% [x1 x2 x3 x4] = disperse(array); | |
% | |
% DISPERSE generalizes to arbitrary dimensions, and is extended to follow | |
% analogous behavior on cell arrays and structure arrays. See the html | |
% documentation for more details and examples. | |
% | |
% Example: | |
% Grab the color channels from an RGB image: | |
% [r g b] = disperse(im); | |
% Sam Hallman | |
% shallman@uci.edu | |
% May 26, 2010 | |
function varargout = disperse(x) | |
% num2cell on column vectors is problematic | |
if ndims(x)==2 && size(x,2)==1 | |
x = x'; | |
end | |
if isnumeric(x) || ischar(x) || islogical(x) || isstruct(x) | |
dims = 1:ndims(x)-1; | |
varargout = num2cell(x,dims); | |
elseif iscell(x) | |
if size(x,1) == 1 | |
varargout = x; | |
else | |
dims = 1:ndims(x)-1; | |
varargout = num2cell(x,dims); | |
end | |
else | |
error('unknown data type'); | |
end | |
endfunction |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment