use crate::engine_state::EngineState;
use crate::scene::{RenderScene, SolidDisplay};
use std::collections::HashSet;
pub(crate) fn named_visibility(
names: impl IntoIterator<Item = String>,
hidden: &HashSet<String>,
) -> Vec<(String, bool)> {
names.into_iter().map(|name| {
let visible = !hidden.contains(&name);
(name, visible)
}).collect()
}
pub(crate) fn named_visibility_json(entries: Vec<(String, bool)>) -> String {
let list: Vec<serde_json::Value> = entries.into_iter()
.map(|(name, visible)| serde_json::json!({ "name": name, "visible": visible }))
.collect();
serde_json::Value::Array(list).to_string()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EntityKind {
Face,
Edge,
Vertex,
}
impl EntityKind {
pub fn parse(kind: &str) -> Option<Self> {
match kind.to_ascii_lowercase().as_str() {
"face" => Some(Self::Face),
"edge" => Some(Self::Edge),
"vertex" => Some(Self::Vertex),
_ => None,
}
}
pub fn as_str(self) -> &'static str {
match self {
Self::Face => "face",
Self::Edge => "edge",
Self::Vertex => "vertex",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GroupState {
All,
Partial,
None,
}
impl GroupState {
pub fn as_str(self) -> &'static str {
match self {
Self::All => "all",
Self::Partial => "partial",
Self::None => "none",
}
}
}
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct EntityVisibility {
hidden_faces: HashSet<usize>,
hidden_edges: HashSet<usize>,
hidden_vertices: HashSet<usize>,
}
impl EntityVisibility {
fn set_of(&self, kind: EntityKind) -> &HashSet<usize> {
match kind {
EntityKind::Face => &self.hidden_faces,
EntityKind::Edge => &self.hidden_edges,
EntityKind::Vertex => &self.hidden_vertices,
}
}
fn set_mut(&mut self, kind: EntityKind) -> &mut HashSet<usize> {
match kind {
EntityKind::Face => &mut self.hidden_faces,
EntityKind::Edge => &mut self.hidden_edges,
EntityKind::Vertex => &mut self.hidden_vertices,
}
}
pub fn is_visible(&self, kind: EntityKind, index: usize) -> bool {
!self.set_of(kind).contains(&index)
}
pub fn any_hidden(&self, kind: EntityKind) -> bool {
!self.set_of(kind).is_empty()
}
pub fn set_visible(&mut self, kind: EntityKind, index: usize, visible: bool) {
if visible {
self.set_mut(kind).remove(&index);
} else {
self.set_mut(kind).insert(index);
}
}
pub fn set_group_visible(&mut self, kind: EntityKind, count: usize, visible: bool) {
let set = self.set_mut(kind);
set.clear();
if !visible {
set.extend(0..count);
}
}
pub fn group_state(&self, kind: EntityKind, count: usize) -> GroupState {
if count == 0 {
return GroupState::All;
}
let hidden = self.set_of(kind).len();
if hidden == 0 {
GroupState::All
} else if hidden >= count {
GroupState::None
} else {
GroupState::Partial
}
}
pub fn is_face_visible(&self, index: usize) -> bool {
self.is_visible(EntityKind::Face, index)
}
pub fn is_edge_visible(&self, index: usize) -> bool {
self.is_visible(EntityKind::Edge, index)
}
pub fn is_vertex_visible(&self, index: usize) -> bool {
self.is_visible(EntityKind::Vertex, index)
}
pub fn any_face_hidden(&self) -> bool {
self.any_hidden(EntityKind::Face)
}
pub fn any_edge_hidden(&self) -> bool {
self.any_hidden(EntityKind::Edge)
}
pub fn any_vertex_hidden(&self) -> bool {
self.any_hidden(EntityKind::Vertex)
}
pub fn all_hidden(&self, kind: EntityKind, count: usize) -> bool {
count > 0 && self.set_of(kind).len() >= count
}
pub fn all_vertices_hidden(&self, count: usize) -> bool {
self.all_hidden(EntityKind::Vertex, count)
}
}
fn entity_count(solid: &SolidDisplay, kind: EntityKind) -> usize {
match kind {
EntityKind::Face => solid.faces.len(),
EntityKind::Edge => solid.edges.len(),
EntityKind::Vertex => solid.vertices.len(),
}
}
impl RenderScene {
pub fn set_entity_visible(
&mut self,
solid: &str,
kind: EntityKind,
index: usize,
visible: bool,
) -> bool {
match self.solid_mut(solid) {
Some(s) => {
s.visibility.set_visible(kind, index, visible);
true
}
None => false,
}
}
pub fn set_group_visible(&mut self, solid: &str, kind: EntityKind, visible: bool) -> bool {
let Some(count) = self.solid(solid).map(|s| entity_count(s, kind)) else {
return false;
};
if let Some(s) = self.solid_mut(solid) {
s.visibility.set_group_visible(kind, count, visible);
}
true
}
pub fn entity_visible(&self, solid: &str, kind: EntityKind, index: usize) -> Option<bool> {
self.solid(solid).map(|s| s.visibility.is_visible(kind, index))
}
pub fn group_visibility(&self, solid: &str, kind: EntityKind) -> Option<GroupState> {
self.solid(solid)
.map(|s| s.visibility.group_state(kind, entity_count(s, kind)))
}
}
impl EngineState {
pub fn set_entity_visible(
&mut self,
solid: &str,
kind: EntityKind,
index: usize,
visible: bool,
) -> bool {
let ok = self.scene.set_entity_visible(solid, kind, index, visible);
if ok {
self.dirty = true;
}
ok
}
pub fn set_group_visible(&mut self, solid: &str, kind: EntityKind, visible: bool) -> bool {
let ok = self.scene.set_group_visible(solid, kind, visible);
if ok {
self.dirty = true;
}
ok
}
pub fn entity_visible(&self, solid: &str, kind: EntityKind, index: usize) -> Option<bool> {
self.scene.entity_visible(solid, kind, index)
}
pub fn group_visibility(&self, solid: &str, kind: EntityKind) -> Option<GroupState> {
self.scene.group_visibility(solid, kind)
}
pub fn scene_visibility_json(&self) -> String {
let kinds = [
("faces", EntityKind::Face),
("edges", EntityKind::Edge),
("vertices", EntityKind::Vertex),
];
let solids: Vec<serde_json::Value> = self
.scene
.solids()
.iter()
.map(|solid| {
let mut obj = serde_json::Map::new();
obj.insert("name".into(), serde_json::json!(solid.name));
obj.insert("visible".into(), serde_json::json!(solid.visible));
for (key, kind) in kinds {
let count = entity_count(solid, kind);
let states: Vec<bool> =
(0..count).map(|i| solid.visibility.is_visible(kind, i)).collect();
obj.insert(
key.into(),
serde_json::json!({
"group": solid.visibility.group_state(kind, count).as_str(),
"states": states,
}),
);
}
serde_json::Value::Object(obj)
})
.collect();
serde_json::Value::Array(solids).to_string()
}
}