Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

### Added

- `plot_geometry`, `plot_distribution`, `plot_combined_analysis`, `plot_section_polars`,
`plot_airfoil_fit` and `plot_airfoils` take `show_title=true`; with `false` the title
is not drawn, and still names the saved file and window.
- The panel plots (`plot!(ax, panel)`, `plot!(ax, body)`, `plot(panel)`, `plot(body)`)
take `border_color`, default `:black`, for the panel outlines.

Expand Down
78 changes: 44 additions & 34 deletions ext/VortexStepMethodMakieExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ end

"""
create_geometry_plot_makie(body_aero::BodyAerodynamics, title,
view_elevation, view_azimuth; zoom=1.8)
view_elevation, view_azimuth; zoom=0.5, show_title=true)

Create a 3D Makie plot of wing geometry including panels and filaments.

Expand All @@ -630,17 +630,19 @@ Create a 3D Makie plot of wing geometry including panels and filaments.
- `view_azimuth`: initial view azimuth angle [°]

# Keyword arguments
- `zoom`: zoom factor (default: 1.8)
- `zoom`: zoom factor (default: 0.5)
- `show_title`: draw `title` above the axis (default: true)
"""
function create_geometry_plot_makie(body_aero::BodyAerodynamics, title,
view_elevation, view_azimuth; zoom=0.5)
view_elevation, view_azimuth; zoom=0.5, show_title=true)
panels = body_aero.panels
va_vec = getfield(body_aero, :va_vec)

# Create figure
fig = Figure(size=(1400, 1400))
ax = Axis3(fig[1, 1];
title=title,
titlevisible=show_title,
xlabel="x", ylabel="y", zlabel="z",
aspect=:data,
azimuth=deg2rad(view_azimuth),
Expand Down Expand Up @@ -698,7 +700,8 @@ end
plot_geometry(body_aero::BodyAerodynamics, title;
data_type=nothing, save_path=nothing,
is_save=false, is_show=false,
view_elevation=15, view_azimuth=-120, use_tex=false)
view_elevation=15, view_azimuth=-120, use_tex=false,
show_title=true)

Makie implementation of [`plot_geometry`](@ref).

Expand All @@ -714,6 +717,7 @@ Makie implementation of [`plot_geometry`](@ref).
- `view_elevation`: View elevation angle in degrees (default: 15)
- `view_azimuth`: View azimuth angle in degrees (default: -120)
- `use_tex`: Ignored for Makie (default: false)
- `show_title`: Whether to draw the title; it names the files either way (default: true)
"""
function VortexStepMethod.plot_geometry(body_aero::BodyAerodynamics, title;
data_type=nothing,
Expand All @@ -722,27 +726,21 @@ function VortexStepMethod.plot_geometry(body_aero::BodyAerodynamics, title;
is_show=false,
view_elevation=15,
view_azimuth=-120,
use_tex=false)
use_tex=false,
show_title=true)

if is_save
# Angled view
fig = create_geometry_plot_makie(body_aero, "$(title)_angled_view", 15, -120)
save_plot(fig, save_path, "$(title)_angled_view", data_type=data_type)

# Top view
fig = create_geometry_plot_makie(body_aero, "$(title)_top_view", 90, 0)
save_plot(fig, save_path, "$(title)_top_view", data_type=data_type)

# Front view
fig = create_geometry_plot_makie(body_aero, "$(title)_front_view", 0, 0)
save_plot(fig, save_path, "$(title)_front_view", data_type=data_type)

# Side view
fig = create_geometry_plot_makie(body_aero, "$(title)_side_view", 0, -90)
save_plot(fig, save_path, "$(title)_side_view", data_type=data_type)
views = (angled=(15, -120), top=(90, 0), front=(0, 0), side=(0, -90))
for (view_name, (elevation, azimuth)) in pairs(views)
view_title = "$(title)_$(view_name)_view"
fig = create_geometry_plot_makie(body_aero, view_title, elevation, azimuth;
show_title)
save_plot(fig, save_path, view_title; data_type)
end
end

fig = create_geometry_plot_makie(body_aero, title, view_elevation, view_azimuth)
fig = create_geometry_plot_makie(body_aero, title, view_elevation, view_azimuth;
show_title)

is_show && show_plot(fig; name=title)

Expand All @@ -761,7 +759,8 @@ span_axis(position, title, ylabel) =
"""
plot_distribution(y_coordinates_list, results_list, label_list;
title="spanwise_distribution", data_type=nothing,
save_path=nothing, is_save=false, is_show=true, use_tex=false)
save_path=nothing, is_save=false, is_show=true, use_tex=false,
show_title=true)

Makie implementation of [`plot_distribution`](@ref).

Expand All @@ -777,22 +776,24 @@ Makie implementation of [`plot_distribution`](@ref).
- `is_save`: Whether to save (default: false)
- `is_show`: Whether to display (default: true)
- `use_tex`: Ignored for Makie (default: false)
- `show_title`: Whether to draw the title; it names the file either way (default: true)
"""
function VortexStepMethod.plot_distribution(y_coordinates_list, results_list, label_list;
title="spanwise_distribution",
data_type=nothing,
save_path=nothing,
is_save=false,
is_show=true,
use_tex=false)
use_tex=false,
show_title=true)

length(results_list) == length(label_list) || throw(ArgumentError(
"Number of results ($(length(results_list))) must match labels ($(length(label_list)))"
))

# Create figure with 3x3 grid
fig = Figure(size=(1600, 1000))
Label(fig[0, :], title, fontsize=20)
show_title && Label(fig[0, :], title, fontsize=20)

# Row 1: CL, CD, Gamma
ax_cl = span_axis(fig[1, 1], "CL Distribution", "Lift Coefficient CL")
Expand Down Expand Up @@ -1124,7 +1125,8 @@ end
view_elevation=15, view_azimuth=-120,
is_show=true, use_tex=false,
literature_path_list=String[],
data_type=".png", save_path=nothing, is_save=false)
data_type=".png", save_path=nothing, is_save=false,
show_title=true)

Makie implementation of [`plot_combined_analysis`](@ref).

Expand Down Expand Up @@ -1154,6 +1156,7 @@ Makie implementation of [`plot_combined_analysis`](@ref).
- `is_save`: Save plots to files (default: false)
- `cl_over_cd`: Plot CL/CD vs angle instead of CL vs CD (default: true)
- `angle_of_attack_for_spanwise_distribution`: AoA for spanwise plots (default: 5.0)
- `show_title`: Whether to draw the overall title (default: true)
"""
function VortexStepMethod.plot_combined_analysis(
solver,
Expand All @@ -1177,6 +1180,7 @@ function VortexStepMethod.plot_combined_analysis(
is_save=false,
angle_of_attack_for_spanwise_distribution=5.0,
cl_over_cd=true,
show_title=true,
)
# Normalize inputs to arrays for consistent handling
solvers = solver isa Vector ? solver : [solver]
Expand Down Expand Up @@ -1218,7 +1222,7 @@ function VortexStepMethod.plot_combined_analysis(
# Fallback if screen detection fails
Figure(size=(1800, 1200))
end
Label(fig[0, 1:2], title, fontsize=20, font=:bold)
show_title && Label(fig[0, 1:2], title, fontsize=20, font=:bold)

# Use first body_aero for geometry and polar data display
first_body = body_aeros[1]
Expand Down Expand Up @@ -1489,7 +1493,7 @@ Implementation of [`plot_section_polars`](@ref); rendered through `MakieControlP
function VortexStepMethod.plot_section_polars(body_aero::BodyAerodynamics;
panels=eachindex(body_aero.panels), alphas=deg2rad.(-20:0.5:30), delta=nothing,
is_show::Bool=true, is_save::Bool=false, save_path=nothing,
data_type::String=".png")
data_type::String=".png", show_title::Bool=true)

panel_indices = vcat(panels)
chosen_panels = body_aero.panels[panel_indices]
Expand All @@ -1499,7 +1503,8 @@ function VortexStepMethod.plot_section_polars(body_aero::BodyAerodynamics;
for (i, panel) in zip(panel_indices, chosen_panels)]

plt = MakieControlPlots.plotx(rad2deg.(alphas), cl, cd, cm;
xlabel="α [deg]", ylabels=["cl", "cd", "cm"], title="Section polars",
xlabel="α [deg]", ylabels=["cl", "cd", "cm"],
title=show_title ? "Section polars" : "",
labels=[labels], disp=(is_show || is_save))

if is_save && !isnothing(save_path)
Expand Down Expand Up @@ -1737,7 +1742,8 @@ function ObjAdapter.plot_slices_3d(path::String; n_slices::Int=10, rotation=I,
end

"""
plot_airfoil_fit(x::Vector, y::Vector; title="Airfoil Fit", is_show=true)
plot_airfoil_fit(x::Vector, y::Vector; title="Airfoil Fit", is_show=true,
show_title=true)

Plot a single airfoil with its Kulfan CST fit.

Expand All @@ -1747,15 +1753,17 @@ Plot a single airfoil with its Kulfan CST fit.
# Keyword Arguments
- `title`: Plot title
- `is_show`: Display figure
- `show_title`: Draw the title; it names the window either way

# Returns
- Makie Figure object and the fitted `KulfanParameters`
"""
function ObjAdapter.plot_airfoil_fit(x::Vector, y::Vector; title::String="Airfoil Fit",
is_show::Bool=true)
is_show::Bool=true, show_title::Bool=true)
fig = Figure(size=(800, 400))
ax = Axis(fig[1, 1];
title=title,
titlevisible=show_title,
xlabel="x/c",
ylabel="y/c",
aspect=DataAspect())
Expand Down Expand Up @@ -1793,7 +1801,7 @@ end
"""
plot_airfoils(geometry_file; overlay=nothing, symmetric=false,
idxs=nothing, n_cols=3, is_show=true, is_save=false,
save_path=nothing, data_type=".png")
save_path=nothing, data_type=".png", show_title=true)

Makie implementation of [`plot_airfoils`](@ref).

Expand All @@ -1804,11 +1812,12 @@ becomes unreadable. Both modes show the raw `_raw.dat` slice points as dots with
the fitted airfoil as a line. Pass `idxs` (e.g. `idxs=[1]`) to plot only those
airfoils by position; otherwise `symmetric=true` shows just the first half of the
sections (the wing is mirror-symmetric, so the other half is redundant).
`show_title=false` leaves the `"Airfoils: <file>"` title off the figure.
"""
function ObjAdapter.plot_airfoils(geometry_file::String;
overlay=nothing, symmetric::Bool=false, idxs=nothing, n_cols::Int=3,
is_show::Bool=true, is_save::Bool=false, save_path=nothing,
data_type::String=".png")
data_type::String=".png", show_title::Bool=true)

airfoils = ObjAdapter.airfoils_from_yaml(geometry_file)
isempty(airfoils) && error("No airfoils with a dat_file found in $geometry_file")
Expand All @@ -1826,7 +1835,8 @@ function ObjAdapter.plot_airfoils(geometry_file::String;
ids = [af.id for af in airfoils]
crange = (minimum(ids), maximum(ids))
fig = Figure(size=(900, 600))
ax = Axis(fig[1, 1]; title, xlabel="x/c", ylabel="y/c", aspect=DataAspect())
ax = Axis(fig[1, 1]; title, titlevisible=show_title, xlabel="x/c", ylabel="y/c",
aspect=DataAspect())
for af in airfoils
isempty(af.x_raw) || scatter!(ax, af.x_raw, af.y_raw;
color=af.id, colorrange=crange, colormap=:viridis, markersize=3)
Expand All @@ -1837,7 +1847,7 @@ function ObjAdapter.plot_airfoils(geometry_file::String;
ncol = min(n_cols, n)
nrow = ceil(Int, n / ncol)
fig = Figure(size=(380 * ncol, 320 * nrow))
Label(fig[0, :], title, fontsize=16)
show_title && Label(fig[0, :], title, fontsize=16)
for (i, af) in enumerate(airfoils)
ax = Axis(fig[div(i - 1, ncol) + 1, mod1(i, ncol)];
title="Airfoil $(af.id)", xlabel="x/c", ylabel="y/c",
Expand Down
4 changes: 4 additions & 0 deletions src/VortexStepMethod.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Plot wing geometry from different viewpoints and optionally save/show plots.
- `view_elevation`: initial view elevation angle in degrees (default: `15`)
- `view_azimuth`: initial view azimuth angle in degrees (default: `-120`)
- `use_tex`: use external `pdflatex` for rendering (default: `false`; ignored by Makie)
- `show_title`: draw the title; it names the saved files either way (default: `true`)
"""
function plot_geometry end

Expand All @@ -97,6 +98,7 @@ Plot spanwise distributions of aerodynamic properties.
- `is_save`: whether to save (default: `false`)
- `is_show`: whether to display (default: `true`)
- `use_tex`: use external `pdflatex` for rendering (default: `false`; ignored by Makie)
- `show_title`: draw the title; it names the saved file either way (default: `true`)
"""
function plot_distribution end

Expand Down Expand Up @@ -172,6 +174,7 @@ in sequence.
- `save_path`: directory to save files (default: `nothing`)
- `is_save`: whether to save (default: `false`)
- `cl_over_cd`: plot CL/CD vs angle (default: `true`)
- `show_title`: draw the overall title (default: `true`)
"""
function plot_combined_analysis end

Expand All @@ -196,6 +199,7 @@ Rendered through `MakieControlPlots`; returns its plot object.
- `is_save`: whether to save (default: `false`)
- `save_path`: directory to save the figure (default: `nothing`)
- `data_type`: file extension for saving (default: `".png"`)
- `show_title`: draw the title (default: `true`)
"""
function plot_section_polars end

Expand Down
74 changes: 74 additions & 0 deletions test/plotting/test_plotting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@ using Test

const makie_ext = Base.get_extension(VortexStepMethod, :VortexStepMethodMakieExt)

"""
drawn_titles(fig) -> Vector{String}

Texts of the `Label`s and of the visible `Axis`/`Axis3` titles drawn on `fig`.
"""
function drawn_titles(fig)
titles = String[]
for block in fig.content
if block isa Label
push!(titles, string(block.text[]))
elseif block isa Union{Axis, Axis3} && block.titlevisible[]
push!(titles, string(block.title[]))
end
end
return titles
end

global ram_wing = ram_air_matrix_wing(; n_panels=20, n_sections=4,
alpha_range=deg2rad.(-1:1.0:1),
delta_range=deg2rad.(-1:1.0:1))
Expand Down Expand Up @@ -166,6 +183,37 @@ end
)
@test fig isa Figure

@testset "show_title=false hides the title but still names the file" begin
fig = plot_geometry(body_aero, "Hidden geometry"; is_show=false)
@test "Hidden geometry" in drawn_titles(fig)
fig = plot_geometry(body_aero, "Hidden geometry"; data_type=".png",
save_path=save_dir, is_save=true, is_show=false, show_title=false)
@test isempty(drawn_titles(fig))
@test isfile(joinpath(save_dir, "Hidden_geometry_top_view.png"))

distribution_args = ([y_coordinates], [results_vsm], ["VSM"])
fig = plot_distribution(distribution_args...; title="Hidden distribution",
is_show=false)
@test "Hidden distribution" in drawn_titles(fig)
fig = plot_distribution(distribution_args...; title="Hidden distribution",
data_type=".png", save_path=save_dir, is_save=true, is_show=false,
show_title=false)
@test "Hidden distribution" ∉ drawn_titles(fig)
@test "CL Distribution" in drawn_titles(fig)
@test isfile(joinpath(save_dir, "Hidden_distribution.png"))

combined_kwargs = (angle_range=range(0, 10, 2), va, is_show=false)
fig = plot_combined_analysis(vsm_solver, body_aero, results_vsm;
title="Hidden combined", combined_kwargs...)
@test "Hidden combined" in drawn_titles(fig)
fig = plot_combined_analysis(vsm_solver, body_aero, results_vsm;
title="Hidden combined", data_type=".png", save_path=save_dir,
is_save=true, show_title=false, combined_kwargs...)
@test "Hidden combined" ∉ drawn_titles(fig)
@test "Wing Geometry" in drawn_titles(fig)
@test isfile(joinpath(save_dir, "Hidden_combined.png"))
end

@testset "round-off CS plots flat, a varying CS keeps its autoscale" begin
fig = Figure()
ax_noise = Axis(fig[1, 1])
Expand Down Expand Up @@ -625,6 +673,32 @@ end
end
end

@testset "show_title=false hides the airfoil and section polar titles" begin
body_aero, _ = create_body_aero_with_skin()
@test plot_section_polars(body_aero; is_show=false).title == "Section polars"
@test plot_section_polars(body_aero; is_show=false, show_title=false).title == ""

_, geometry_file = ram_air_matrix_dir(; n_sections=4,
alpha_range=deg2rad.(-1:1.0:1), delta_range=deg2rad.(-1:1.0:1))
obj_adapter = VortexStepMethod.ObjAdapter
airfoil = first(obj_adapter.airfoils_from_yaml(geometry_file))
fig, _ = obj_adapter.plot_airfoil_fit(airfoil.x, airfoil.y; title="Hidden fit",
is_show=false)
@test "Hidden fit" in drawn_titles(fig)
fig, _ = obj_adapter.plot_airfoil_fit(airfoil.x, airfoil.y; title="Hidden fit",
is_show=false, show_title=false)
@test drawn_titles(fig) == ["Kulfan Parameters"]

airfoils_title = "Airfoils: geometry.yaml"
for overlay in (false, true)
fig = obj_adapter.plot_airfoils(geometry_file; overlay, is_show=false)
@test airfoils_title in drawn_titles(fig)
fig = obj_adapter.plot_airfoils(geometry_file; overlay, is_show=false,
show_title=false)
@test airfoils_title ∉ drawn_titles(fig)
end
end

@testset "Audit slices (Makie)" begin
# An all-NaN deflected .dat reads as empty; here a header-only file stands in.
gen_dir, _ = ram_air_matrix_dir(; n_sections=4,
Expand Down
Loading