forked from 1b-agent/opencadstudio-upstream
Associate hatch boundaries from internal points and selected sources
This commit is contained in:
1 parent
49d1125530
commit
1039f51abf
5 files changed
+74
-8
No files matched your search
@@ -4462,7 +4462,16 @@ impl OpenCADStudio {
|
||||
self.command_line.push_info("HATCHEDIT: hatch is already associative.");
|
||||
self.tabs[i].active_cmd=None;
|
||||
}else{
|
||||
let command=crate::modules::draw::draw::hatchedit::HatcheditCommand::for_association(handle,name,scale,angle);
|
||||
let plane=match self.tabs[i].scene.document.get_entity(handle) {
|
||||
Some(acadrust::EntityType::Hatch(h))=>{
|
||||
let storage=crate::entities::curve::ocs_plane(h.normal,h.elevation);
|
||||
crate::command::WorkingPlane::new(glam::DVec3::from_array(storage.origin),glam::DVec3::from_array(storage.x_axis),glam::DVec3::from_array(storage.y_axis))
|
||||
},
|
||||
_=>self.tabs[i].ucs_xform().working_plane(),
|
||||
};
|
||||
let mut sources=self.tabs[i].scene.boundary_sources_on_plane(plane,1e-6);
|
||||
sources.remove(&handle);
|
||||
let command=crate::modules::draw::draw::hatchedit::HatcheditCommand::for_association(handle,name,scale,angle,plane,sources);
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd=Some(Box::new(command));
|
||||
@@ -4632,6 +4641,14 @@ impl OpenCADStudio {
|
||||
.scene
|
||||
.edit_hatch_boundary_handles(handle, &handles, false);
|
||||
}
|
||||
HatchEditOperation::AssociatePaths(paths) => {
|
||||
if paths.is_empty()||paths.iter().any(|path|path.boundary_handles.is_empty()||path.boundary_handles.iter().any(|source|self.tabs[i].scene.document.get_entity(*source).is_none())) {
|
||||
self.discard_last_undo_entry(i);
|
||||
self.command_line.push_error("HATCHEDIT: associated boundary is no longer available.");
|
||||
return Task::none();
|
||||
}
|
||||
self.tabs[i].scene.replace_hatch_association(handle,paths);
|
||||
}
|
||||
HatchEditOperation::AssociateBoundaries(handles) => {
|
||||
let plane=match self.tabs[i].scene.document.get_entity(handle) {
|
||||
Some(acadrust::EntityType::Hatch(h))=>{
|
||||
|
||||
@@ -27,6 +27,7 @@ pub enum HatchEditOperation {
|
||||
RecreateBoundary { associate: bool, region: bool },
|
||||
BeginAssociate,
|
||||
AssociateBoundaries(Vec<Handle>),
|
||||
AssociatePaths(Vec<acadrust::entities::BoundaryPath>),
|
||||
DrawOrderBoundary { above: bool },
|
||||
Separate,
|
||||
AddBoundaries(Vec<Handle>),
|
||||
|
||||
@@ -37,6 +37,9 @@ pub struct HatcheditCommand {
|
||||
current_color: acadrust::types::Color,
|
||||
current_transparency: acadrust::types::Transparency,
|
||||
boundary_region: bool,
|
||||
association_sources: Option<(crate::command::WorkingPlane,rustc_hash::FxHashMap<Handle,crate::scene::BoundarySource>)>,
|
||||
association_paths: Vec<acadrust::entities::BoundaryPath>,
|
||||
association_missed: bool,
|
||||
}
|
||||
|
||||
impl HatcheditCommand {
|
||||
@@ -54,6 +57,9 @@ impl HatcheditCommand {
|
||||
current_color: acadrust::types::Color::ByLayer,
|
||||
current_transparency: acadrust::types::Transparency::ByLayer,
|
||||
boundary_region: false,
|
||||
association_sources: None,
|
||||
association_paths: Vec::new(),
|
||||
association_missed: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +88,9 @@ impl HatcheditCommand {
|
||||
current_color: acadrust::types::Color::ByLayer,
|
||||
current_transparency: acadrust::types::Transparency::ByLayer,
|
||||
boundary_region: false,
|
||||
association_sources: None,
|
||||
association_paths: Vec::new(),
|
||||
association_missed: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +113,17 @@ impl HatcheditCommand {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn for_association(handle:Handle,name:String,scale:f32,angle:f32)->Self {
|
||||
pub fn for_association(handle:Handle,name:String,scale:f32,angle:f32,plane:crate::command::WorkingPlane,sources:rustc_hash::FxHashMap<Handle,crate::scene::BoundarySource>)->Self {
|
||||
let mut command=Self::with_handle(handle,name,scale,angle,false);
|
||||
command.input=Some("associate-select");command
|
||||
command.input=Some("associate-point");command.association_sources=Some((plane,sources));command
|
||||
}
|
||||
fn add_association_rings(&mut self,rings:Vec<Vec<[f64;2]>>,sources:&rustc_hash::FxHashMap<Handle,crate::scene::BoundarySource>) {
|
||||
let exterior=cadkernel::geom2d::ring_nesting_depths(&rings).into_iter().map(|depth|depth==0).collect::<Vec<_>>();
|
||||
let paths=crate::scene::exact_hatch_paths(&rings,&exterior,sources,1e-6);
|
||||
self.association_missed=paths.is_empty()||paths.len()!=rings.len()||paths.iter().any(|path|path.boundary_handles.is_empty());
|
||||
if !self.association_missed {
|
||||
for path in paths {if !self.association_paths.contains(&path){self.association_paths.push(path);}}
|
||||
}
|
||||
}
|
||||
pub fn with_appearance(mut self,entity:Option<&acadrust::EntityType>,current_color:acadrust::types::Color,current_transparency:acadrust::types::Transparency)->Self {
|
||||
self.source_appearance=entity.map(|e|{let c=e.common();(c.color,c.layer.clone(),c.transparency)});
|
||||
@@ -162,6 +179,8 @@ impl CadCommand for HatcheditCommand {
|
||||
"boundary-type"=>"Enter type of boundary object [Region/Polyline] <Polyline>:",
|
||||
"boundary-associate"=>"Reassociate hatch with new boundary? [Yes/No] <No>:",
|
||||
"associate-select"=>"Select boundary objects:",
|
||||
"associate-point" if self.association_missed=>"No closed boundary found. Specify internal point or [Select objects]:",
|
||||
"associate-point"=>"Specify internal point or [Select objects]:",
|
||||
_=>"Specify value:",
|
||||
}.into();
|
||||
}
|
||||
@@ -188,7 +207,13 @@ impl CadCommand for HatcheditCommand {
|
||||
}
|
||||
fn is_selection_gathering(&self)->bool {self.input==Some("associate-select")}
|
||||
fn on_selection_complete(&mut self,handles:Vec<Handle>)->CmdResult {
|
||||
self.boundary_selection=handles;CmdResult::NeedPoint
|
||||
self.boundary_selection=handles.clone();
|
||||
if let Some((_,sources))=&self.association_sources {
|
||||
let sources=sources.iter().filter(|(handle,_)|handles.contains(handle)).map(|(handle,source)|(*handle,source.clone())).collect();
|
||||
let rings=crate::scene::boundary_faces(&sources,1e-6);
|
||||
self.add_association_rings(rings,&sources);
|
||||
}
|
||||
self.input=Some("associate-point");CmdResult::NeedPoint
|
||||
}
|
||||
|
||||
fn on_entity_pick(&mut self, handle: Handle, _pt: DVec3) -> CmdResult {
|
||||
@@ -211,6 +236,7 @@ impl CadCommand for HatcheditCommand {
|
||||
}
|
||||
|
||||
fn options(&self) -> Vec<crate::command::CmdOption> {
|
||||
if self.input==Some("associate-point") {return vec![crate::command::CmdOption::new("Select objects","S")];}
|
||||
if self.input.is_some() {return Vec::new();}
|
||||
if !matches!(self.step, HatcheditStep::EditOptions { .. }) {
|
||||
return Vec::new();
|
||||
@@ -238,6 +264,10 @@ impl CadCommand for HatcheditCommand {
|
||||
use acadrust::types::{Color,Transparency};
|
||||
let appearance=|color,layer,transparency|HatchEditOperation::Appearance{color,layer,transparency};
|
||||
match input {
|
||||
"associate-point"=>{
|
||||
if matches!(keyword.as_str(),"S"|"SELECT"|"SELECT OBJECTS") {self.input=Some("associate-select");}
|
||||
return Some(CmdResult::NeedPoint);
|
||||
},
|
||||
"color"=>{
|
||||
if matches!(keyword.as_str(),"T"|"TRUECOLOR") {self.input=Some("truecolor");return Some(CmdResult::NeedPoint);}
|
||||
let color=match keyword.as_str(){"."=>Some(self.current_color),"BYLAYER"=>Some(Color::ByLayer),"BYBLOCK"=>Some(Color::ByBlock),
|
||||
@@ -403,7 +433,16 @@ impl CadCommand for HatcheditCommand {
|
||||
Some(CmdResult::NeedPoint)
|
||||
}
|
||||
|
||||
fn on_point(&mut self, _pt: DVec3) -> CmdResult {
|
||||
fn on_point(&mut self, pt: DVec3) -> CmdResult {
|
||||
if self.input==Some("associate-point") {
|
||||
if let Some((plane,sources))=&self.association_sources {
|
||||
let point=plane.to_local(pt);
|
||||
let sources=sources.clone();
|
||||
if let Some(rings)=crate::scene::model::presspull_model::selected_rings(&sources,[point.x,point.y]) {
|
||||
self.add_association_rings(rings,&sources);
|
||||
}else{self.association_missed=true;}
|
||||
}
|
||||
}
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
@@ -420,8 +459,9 @@ impl CadCommand for HatcheditCommand {
|
||||
Some("angle")=>self.apply_result(self.update_operation()).unwrap_or(CmdResult::Cancel),
|
||||
Some("boundary-type")=>{self.boundary_region=false;self.input=Some("boundary-associate");CmdResult::NeedPoint},
|
||||
Some("boundary-associate")=>self.apply_result(HatchEditOperation::RecreateBoundary{associate:false,region:self.boundary_region}).unwrap_or(CmdResult::Cancel),
|
||||
Some("associate-select")=>if self.boundary_selection.is_empty(){CmdResult::Cancel}else{
|
||||
self.apply_result(HatchEditOperation::AssociateBoundaries(self.boundary_selection.clone())).unwrap_or(CmdResult::Cancel)
|
||||
Some("associate-select")=>{self.input=Some("associate-point");CmdResult::NeedPoint},
|
||||
Some("associate-point")=>if self.association_paths.is_empty(){CmdResult::Cancel}else{
|
||||
self.apply_result(HatchEditOperation::AssociatePaths(self.association_paths.clone())).unwrap_or(CmdResult::Cancel)
|
||||
},
|
||||
_=>CmdResult::Cancel,
|
||||
}
|
||||
|
||||
@@ -628,6 +628,14 @@ pub(crate) fn boundary_entities_from_sources(
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
pub(crate) fn replace_hatch_association(&mut self,handle:Handle,paths:Vec<acadrust::entities::BoundaryPath>) {
|
||||
let Some(EntityType::Hatch(hatch))=self.document.get_entity_mut(handle) else{return;};
|
||||
hatch.paths=paths;
|
||||
hatch.is_associative=true;
|
||||
self.associative_hatch_source_cache.borrow_mut().take();
|
||||
self.refresh_fill_model(handle);
|
||||
}
|
||||
|
||||
pub(crate) fn edit_hatch_boundary_handles(
|
||||
&mut self,
|
||||
hatch_handle: Handle,
|
||||
|
||||
@@ -141,7 +141,7 @@ fn boundary_sources(scene: &Scene, plane: WorkingPlane) -> FxHashMap<Handle, Bou
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn selected_rings(sources: &FxHashMap<Handle, BoundarySource>, point: [f64; 2]) -> Option<Vec<Vec<[f64; 2]>>> {
|
||||
pub(crate) fn selected_rings(sources: &FxHashMap<Handle, BoundarySource>, point: [f64; 2]) -> Option<Vec<Vec<[f64; 2]>>> {
|
||||
let rings = boundary_faces(sources, BOUNDARY_TOLERANCE);
|
||||
let loops = boundary_loops(sources, &rings)?;
|
||||
let tolerance = Tolerance::new(BOUNDARY_TOLERANCE);
|
||||
|
||||
Reference in new issue
Block a user