Skip to content

Commit

Permalink
Rework sort_visible_faces() to account for the FV recent changes. (#1597
Browse files Browse the repository at this point in the history
)

* Add new member to GMTfv

* Pass also the 'i_dz', which fundamental for color interpolation.

* Fixes/improvements in the flatfv() fun.

* Rework sort_visible_faces() to account for the FV recent changes.
  • Loading branch information
joa-quim authored Nov 26, 2024
1 parent 4e69ed3 commit 2385770
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 44 deletions.
4 changes: 2 additions & 2 deletions src/gmt_main.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1228,10 +1228,10 @@ function palette_init(API::Ptr{Nothing}, cpt::GMTcpt)::Ptr{GMT_PALETTE}
rgb_diff = (cpt.cpt[j,4]-cpt.cpt[j,1], cpt.cpt[j,5]-cpt.cpt[j,2], cpt.cpt[j,6]-cpt.cpt[j,3], 0.0)
z_low = cpt.range[j,1]
z_high = cpt.range[j,2]
# GMT6.1 bug does not free "key" but frees "label" and does not see if memory is external. Hence crash or mem leaks
i_dz = 1. / (z_high - z_low)

annot = (j == Pb.n_colors) ? 3 : 1 # Annotations L for all but last which is B(oth)
lut = GMT_LUT(z_low, z_high, glut.i_dz, rgb_low, rgb_high, rgb_diff, glut.hsv_low, glut.hsv_high,
lut = GMT_LUT(z_low, z_high, i_dz, rgb_low, rgb_high, rgb_diff, glut.hsv_low, glut.hsv_high,
glut.hsv_diff, annot, glut.skip, glut.fill, C_NULL, C_NULL)

unsafe_store!(Pb.data, lut, j)
Expand Down
28 changes: 15 additions & 13 deletions src/gmt_types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -298,24 +298,26 @@ GMTdataset(data::Array{Float32,2}) =
The GMTfv struct is used to store a (mostly) triangulated mesh.
The fields of this struct are:
- `verts::AbstractMatrix{T}`: Mx3 Matrix with the data vertices
- `faces`::Vector{<:AbstractMatrix{<:Integer}} A vector of matrices with the faces. Each row is a face
- `faces_view`::Vector{Matrix{Int}} A subset of `faces` with only the visible faces from a certain perspective
- `color`::Vector{Vector{String}} A vector with G option colors for each face
- `bbox`::Vector{Float64} The vertices BoundingBox
- `zscale`::Float64 A multiplicative factor to scale the z values
- `bfculling`::Bool If culling of invisible faces is wished. Default is true
- `isflat`::Vector{Bool} If this is a flat mesh. Default is false
- `proj4::String` Projection string in PROJ4 syntax (Optional)
- `wkt::String` Projection string in WKT syntax (Optional)
- `epsg::Int` EPSG projection code (Optional)
- `verts::AbstractMatrix{T}`: A Mx3 Matrix with the data vertices
- `faces::Vector{<:AbstractMatrix{<:Integer}}`: A vector of matrices with the faces. Each row is a face
- `faces_view::Vector{Matrix{Int}}`: A subset of `faces` with only the visible faces from a certain perspective
- `bbox::Vector{Float64}`: The vertices BoundingBox
- `color::Vector{Vector{String}}`: A vector with G option colors for each face
- `color_vwall::String`: A string for makecpt cmap option argument (e.g. "darkgreen,lightgreen")
- `zscale::Float64`: A multiplicative factor to scale the z values. Default is 1.
- `bfculling::Bool`: If culling of invisible faces is wished. Default is true
- `isflat::Vector{Bool}`: If this is a flat mesh. Default is false
- `proj4::String`: Projection string in PROJ4 syntax (Optional)
- `wkt::String`: Projection string in WKT syntax (Optional)
- `epsg::Int`: EPSG projection code (Optional)
"""
Base.@kwdef mutable struct GMTfv{T<:AbstractFloat} <: AbstractArray{T,2}
verts::AbstractMatrix{T}=Matrix{Float64}(undef,0,0)
faces::Vector{<:AbstractMatrix{<:Integer}}=Vector{Matrix{Int}}(undef,0)
faces_view::Vector{Matrix{Int}}=Vector{Matrix{Int}}(undef,0)
color::Vector{Vector{String}}=[String[]]
bbox::Vector{Float64}=zeros(6)
color::Vector{Vector{String}}=[String[]]
color_vwall::String=""
zscale::Float64=1.0
bfculling::Bool=true
isflat::Vector{Bool}=[false]
Expand All @@ -330,7 +332,7 @@ Base.BroadcastStyle(::Type{<:GMTfv}) = Broadcast.ArrayStyle{GMTfv}()
function Base.similar(bc::Broadcast.Broadcasted{Broadcast.ArrayStyle{GMTfv}}, ::Type{ElType}) where ElType
FV = find4similar(bc.args) # Scan the inputs for the FV:
#GMTfv(similar(Array{ElType}, axes(bc)), FV.faces, FV.faces_view, FV.color, FV.bbox, FV.zscale, FV.bfculling, FV.proj4, FV.wkt, FV.epsg)
GMTfv(FV.verts, FV.faces, FV.faces_view, FV.color, FV.bbox, FV.zscale, FV.bfculling, FV.proj4, FV.wkt, FV.epsg)
GMTfv(FV.verts, FV.faces, FV.faces_view, FV.bbox, FV.color, FV.color_vwall, FV.zscale, FV.bfculling, FV.proj4, FV.wkt, FV.epsg)
end
find4similar(FV::GMTfv, rest) = FV

Expand Down
47 changes: 28 additions & 19 deletions src/psxy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1561,20 +1561,20 @@ function sort_visible_faces(FV::GMTfv, azim, elev; del::Bool=true)::Tuple{GMTfv,
view_vec = [sin_az * cos_el, cos_az * cos_el, sin_el]
projs = Float64[]

#!FV.bfculling && (del = false) # Do not delete if bfculling is set to false (for example if FV is not closed)
#isPlane = (FV.isflat || FV.bbox[1] == FV.bbox[2]) || (FV.bbox[3] == FV.bbox[4]) || (FV.bbox[5] == FV.bbox[6]) # Is this FV a plane?
#isPlane && (del = false) # Planes have no invisibles
#needNormals = isempty(FV.color[1]) # If we have no color, we need to compute the normals

#isPlane && !needNormals && return FV, projs # Nothing to do here in this case.

if (!isempty(FV.color_vwall))
P::Ptr{GMT_PALETTE} = palette_init(G_API[1], gmt("makecpt -T0/1 -C" * FV.color_vwall)); # A pointer to a GMT CPT
rgb = [0.0, 0.0, 0.0, 0.0]
end

FV.faces_view = Vector{Matrix{Int}}(undef,numel(FV.faces))
first_face_vis = true
for k = 1:numel(FV.faces) # Loop over number of face groups (we can have triangles, quads, etc)
isPlane = FV.isflat[k]
needNormals = isempty(FV.color[1]) # If we have no color, we need to compute the normals
isPlane && !needNormals && continue # Nothing to do here in this case.
have_colorwall = length(FV.color) >= k && !isassigned(FV.color[k], 1) && !isempty(FV.color_vwall)
needNormals = have_colorwall || (length(FV.color) >= k && isempty(FV.color[k])) # No color, no normals
(isPlane && !needNormals) && (FV.faces_view[k] = FV.faces[k]; continue) # Nothing more to do in this case.
del = !isPlane && FV.bfculling # bfculling should become a vector too?
have_colors = !isempty(FV.color[1]) # Does this FV have a color for each polygon?
have_colors = length(FV.color) >= k && !isempty(FV.color[k]) # Does this FV has a color for each polygon?

n_faces::Int = size(FV.faces[k], 1) # Number of faces (polygons)
this_face_nverts::Int = size(FV.faces[k], 2)
Expand All @@ -1593,24 +1593,33 @@ function sort_visible_faces(FV::GMTfv, azim, elev; del::Bool=true)::Tuple{GMTfv,
push!(dists, (cx * sin_az + cy * cos_az, cz * sin_el))
end
push!(_projs, this_proj) # But need the normals as stated at the begining of this function
if (have_colorwall)
gmt_get_rgb_from_z(G_API[1], P, this_proj, rgb)
FV.color[k][face] = @sprintf("-G#%.2x%.2x%.2x", round(Int, rgb[1]*255), round(Int, rgb[2]*255), round(Int, rgb[3]*255))
end
end
end

if (isPlane) # Here, FV being a plane we only care about storing the normals
projs = (first_face_vis) ? _projs[ind] : append!(projs, _projs[ind])
first_face_vis = false
continue
end

#if (isPlane) # Here, FV being a plane we only care about storing the normals
#projs = (first_face_vis) ? _projs[ind] : append!(projs, _projs[ind]) # 'ind' may be first time use => error?
#first_face_vis = false
#continue
#end

(have_colorwall) && (FV.color[k] = FV.color[k][isVisible]) # SO FUNCIONA A PRIMEIRA VEZ
data::Matrix{Integer} = del ? FV.faces[k][isVisible, :] : FV.faces[k]
isempty(data) && continue
isempty(data) && continue # These 'continues' leave out #undefs in FV.faces_view that need to be deleted
ind = sortperm(dists)
data = data[ind, :]
(first_face_vis) ? (FV.faces_view = [data]) : append!(FV.faces_view, [data])
FV.faces_view[k] = data
projs = (first_face_vis) ? _projs[ind] : append!(projs, _projs[ind])
have_colors && (FV.color[k] = FV.color[k][ind])
(have_colors || have_colorwall) && (FV.color[k] = FV.color[k][ind])
first_face_vis = false
end

c = [isassigned(FV.faces_view, k) for k = 1:numel(FV.faces_view)]
!all(c) && (FV.faces_view = FV.faces_view[c]) # Delete eventual #undefs

vis = sum(size.(FV.faces_view, 1)) # If = 0, it must have been a plane.
vis > 0 && vis < sum(size.(FV.faces, 1) / 3) &&
@warn("More than 2/3 of the faces found invisible (actually: $(100 - sum(size.(FV.faces_view, 1)) / sum(size.(FV.faces, 1))*100)%). This often indicates that the Z and X,Y units are not the same. Consider setting `bfculling` to false or use the `nocull=true` option, or using the `zscale` field of the `FV` input.")
Expand Down
15 changes: 10 additions & 5 deletions src/solids.jl
Original file line number Diff line number Diff line change
Expand Up @@ -761,14 +761,18 @@ function flatfv(I::Union{GMTimage, AbstractString}; shape=:n, level=0.0, thickne
end
isnoref && return I # A plain image with no coords

x = extrema(view(shape, :, 1)) # xx minmax
y = extrema(view(shape, :, 2))
if (isa(shape, GDtype))
x, y = isa(shape, Vector) ? (shape[1].ds_bbox[1:2], shape[1].ds_bbox[3:4]) : (shape.ds_bbox[1:2], shape.ds_bbox[3:4])
else
x = extrema(view(shape, :, 1)) # xx minmax
y = extrema(view(shape, :, 2))
end
isa(I, AbstractString) && (x[1] < D[1] || x[2] > D[2] || y[1] < D[3] || y[2] > D[4]) &&
error("The 'shape' is outside the image.")
isa(I, GMTimage) && (x[1] < I.range[1] || x[2] > I.range[2] || y[1] < I.range[3] || y[2] > I.range[4]) &&
error("The 'shape' is outside the image.")

return isa(I, AbstractString) ? gmtread(I, R=(x[1], x[2], y[1], y[2]), V=:q) : crop(I, R=(x[1], x[2], y[1], y[2]))
return isa(I, AbstractString) ? gmtread(I, R=(x[1], x[2], y[1], y[2]), V=:q) : crop(I, R=(x[1], x[2], y[1], y[2]))[1]
end

function forceRGB(I)::GMTimage{UInt8, 3}
Expand Down Expand Up @@ -868,9 +872,10 @@ function flatfv(I::Union{GMTimage, AbstractString}; shape=:n, level=0.0, thickne
FV.color, FV.isflat = [cor], [true]
else
cor_wall = Vector{String}(undef, n_wall)
for k = 1:n_wall cor_wall[k] = "-G180" end
#for k = 1:n_wall cor_wall[k] = "-G180" end
FV.color = [cor_wall, cor]
FV.isflat = [true, false]
FV.isflat = [false, true]
FV.color_vwall = "140,220"
end
return FV
end
10 changes: 5 additions & 5 deletions src/utils_types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -700,21 +700,21 @@ Create a FacesVertices object from a matrix of faces indices and another matrix
surfaces (cylinders for example).
- `V`: A Mx3 matrix of vertices.
### Keyword args
### Kargs
- `proj` or `proj4`: A proj4 string for setting the Coordinate Referencing System
- `wkt`: A WKT SRS.
- `epsg`: Same as `proj` but using an EPSG code
"""
function fv2fv(F::Vector{<:AbstractMatrix{<:Integer}}, V; zscale=1.0, bfculling=true, proj="", proj4="", wkt="", epsg=0)::GMTfv
function fv2fv(F::Vector{<:AbstractMatrix{<:Integer}}, V; color_vwall::String="", zscale=1.0, bfculling=true, proj="", proj4="", wkt="", epsg=0)::GMTfv
(isempty(proj4) && !isempty(proj)) && (proj4 = proj) # Allow both proj4 or proj keywords
bbox = extrema(V, dims=1)
isflat = zeros(Bool, length(F)) # Needs thinking
GMTfv(verts=V, faces=F, bbox=[bbox[1][1], bbox[1][2], bbox[2][1], bbox[2][2], bbox[3][1], bbox[3][2]],
zscale=zscale, bfculling=bfculling, isflat=isflat, proj4=proj4, wkt=wkt, epsg=epsg)
color_vwall=color_vwall, zscale=zscale, bfculling=bfculling, isflat=isflat, proj4=proj4, wkt=wkt, epsg=epsg)
end

fv2fv(F::Matrix{<:Integer}, V; zscale=1.0, bfculling=true, proj="", proj4="", wkt="", epsg=0) =
fv2fv([F], V; zscale=zscale, bfculling=bfculling, proj=proj, proj4=proj4, wkt=wkt, epsg=epsg)
fv2fv(F::Matrix{<:Integer}, V; color_vwall::String="", zscale=1.0, bfculling=true, proj="", proj4="", wkt="", epsg=0) =
fv2fv([F], V; color_vwall=color_vwall, zscale=zscale, bfculling=bfculling, proj=proj, proj4=proj4, wkt=wkt, epsg=epsg)

"""
When using Meshing.jl we can use the output of the ``isosurface`` function, "verts, faces" as input to this function.
Expand Down

0 comments on commit 2385770

Please sign in to comment.