@@ -157,24 +157,17 @@ impl Instance {
157157 }
158158 }
159159
160- fn move_pin ( & mut self , pin : Pin , new_pos : Pos2 ) {
161- match & mut self . ty {
160+ fn move_pin_delta ( & self , pin : Pin , new_pos : Pos2 ) -> Vec2 {
161+ match & self . ty {
162162 InstanceType :: Wire ( wire) => {
163- // TODO: Maybe wire.start and wire.end can go to a vector of size 2?
164163 if pin. index == 0 {
165- wire. start = new_pos ;
164+ new_pos - wire. start
166165 } else {
167- wire. end = new_pos ;
166+ new_pos - wire. end
168167 }
169168 }
170- InstanceType :: Gate ( gate) => {
171- let move_vec = new_pos - pin. pos ;
172- gate. pos += move_vec;
173- }
174- InstanceType :: Power ( power) => {
175- let move_vec = new_pos - pin. pos ;
176- power. pos += move_vec;
177- }
169+ InstanceType :: Gate ( _gate) => new_pos - pin. pos ,
170+ InstanceType :: Power ( _power) => new_pos - pin. pos ,
178171 }
179172 }
180173}
@@ -322,7 +315,7 @@ impl PanelDrag {
322315 }
323316}
324317
325- #[ derive( serde:: Deserialize , serde:: Serialize , Default ) ]
318+ #[ derive( serde:: Deserialize , serde:: Serialize , Debug , Default ) ]
326319pub struct CanvasDrag {
327320 id : InstanceId ,
328321 /// Offset from mouse pointer to gate center at drag start
@@ -342,22 +335,82 @@ pub struct Pin {
342335 pub index : u32 ,
343336}
344337
338+ impl Pin {
339+ /// Compute this pin's current world position from its instance.
340+ /// This ignores the stored `pos` and derives from the instance's data.
341+ pub fn _position_from ( & self , ins : & Instance ) -> Pos2 {
342+ match ins. ty {
343+ InstanceType :: Gate ( g) => {
344+ let info = g. kind . graphics ( ) . pins [ self . index as usize ] ;
345+ g. pos + info. offset
346+ }
347+ InstanceType :: Power ( p) => {
348+ let info = p. graphics ( ) . pins [ self . index as usize ] ;
349+ p. pos + info. offset
350+ }
351+ InstanceType :: Wire ( w) => {
352+ if self . index == 0 {
353+ w. start
354+ } else {
355+ w. end
356+ }
357+ }
358+ }
359+ }
360+ }
361+
345362impl Hash for Pin {
346363 fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
347364 self . ins . hash ( state) ;
348365 self . index . hash ( state) ;
349366 }
350367}
351368
352- #[ derive( serde:: Deserialize , serde:: Serialize , Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
369+ #[ derive( serde:: Deserialize , serde:: Serialize , Debug , Eq , Clone , Copy ) ]
353370pub struct Connection {
354371 pin1 : Pin ,
355372 pin2 : Pin ,
356373}
357374
358375impl Connection {
359376 fn new ( pin1 : Pin , pin2 : Pin ) -> Self {
360- Self { pin1, pin2 }
377+ let ( a, b) = if ( pin2. ins , pin2. index ) < ( pin1. ins , pin1. index ) {
378+ ( pin2, pin1)
379+ } else {
380+ ( pin1, pin2)
381+ } ;
382+ Self { pin1 : a, pin2 : b }
383+ }
384+
385+ /// Return pins in the order that starts with pin from instance id
386+ fn get_pin ( & self , moving_instance_id : InstanceId ) -> Option < ( Pin , Pin ) > {
387+ if self . pin1 . ins == moving_instance_id {
388+ Some ( ( self . pin1 , self . pin2 ) )
389+ } else if self . pin2 . ins == moving_instance_id {
390+ Some ( ( self . pin2 , self . pin1 ) )
391+ } else {
392+ None
393+ }
394+ }
395+ }
396+
397+ impl PartialEq for Connection {
398+ fn eq ( & self , other : & Self ) -> bool {
399+ // Order-insensitive equality thanks to normalization
400+ self . pin1 . ins == other. pin1 . ins
401+ && self . pin1 . index == other. pin1 . index
402+ && self . pin2 . ins == other. pin2 . ins
403+ && self . pin2 . index == other. pin2 . index
404+ }
405+ }
406+
407+ impl Hash for Connection {
408+ fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
409+ // Order-insensitive hash thanks to normalization
410+ self . pin1 . ins . hash ( state) ;
411+ self . pin1 . index . hash ( state) ;
412+ self . pin2 . ins . hash ( state) ;
413+ self . pin2 . index . hash ( state) ;
361414 }
362415}
363416
@@ -421,8 +474,8 @@ impl TemplateApp {
421474 ui. add_sized (
422475 vec2 ( 200.0 , 50.0 ) ,
423476 egui:: TextEdit :: multiline ( & mut format ! (
424- "world {:#?}\n conn: {:#?}" ,
425- self . instances, self . connections
477+ "world {:#?}\n conn: {:#?}\n moving: {:#?} \n \n \n " ,
478+ self . instances, self . connections, self . canvas_drag
426479 ) ) ,
427480 )
428481 } ) ;
@@ -652,67 +705,63 @@ impl TemplateApp {
652705 let mut possible_connections = HashSet :: new ( ) ;
653706 for self_ins in & self . instances {
654707 log:: info!( "{self_ins:#?}" ) ;
655- let self_pins = self_ins. pins ( ) ;
656- for self_pin in self_pins {
708+ for self_pin in self_ins. pins ( ) {
657709 for other_ins in & self . instances {
658710 if self_ins. id == other_ins. id {
659711 continue ;
660712 }
661-
662713 for other_pin in other_ins. pins ( ) {
663714 if self_pin. pos . distance ( other_pin. pos ) > threshold {
664715 continue ;
665716 }
666717
667718 log:: info!( "{self_pin:#?}, {other_pin:#?}" ) ;
668719 let t = Connection :: new ( self_pin, other_pin) ;
669- let t_other = Connection :: new ( other_pin, self_pin) ;
670- // TODO: Use the hashset hashing instead of this check
671- let found = possible_connections. contains ( & t)
672- || possible_connections. contains ( & t_other) ;
720+ // To prevent pin1, pin2 and pin2, pin1 connections
721+ let found = possible_connections. contains ( & t) ;
673722 if !found {
674723 possible_connections. insert ( t) ;
675724 }
676725 }
677726 }
678727 }
679728 }
680- // paint connected pins (iterate in a stable order)
681- let mut conns: Vec < _ > = possible_connections. iter ( ) . collect ( ) ;
682- conns. sort_by_key ( |c| {
683- (
684- c. pin1 . pos . x . to_bits ( ) ,
685- c. pin1 . pos . y . to_bits ( ) ,
686- c. pin2 . pos . x . to_bits ( ) ,
687- c. pin2 . pos . y . to_bits ( ) ,
688- )
689- } ) ;
690- for conn in conns {
691- if conn. pin1 . ins == moving_instance_id {
692- ui. painter ( )
693- . circle_filled ( conn. pin1 . pos , 10.0 , Color32 :: LIGHT_YELLOW ) ;
694- } else if conn. pin2 . ins == moving_instance_id {
729+ // TODO: inefficient but okay for now. We want to highlight connections for moving
730+ // object.
731+ for conn in & possible_connections {
732+ if let Some ( ( pin, _) ) = conn. get_pin ( moving_instance_id) {
695733 ui. painter ( )
696- . circle_filled ( conn . pin2 . pos , 10.0 , Color32 :: LIGHT_YELLOW ) ;
734+ . circle_filled ( pin . pos , 10.0 , Color32 :: LIGHT_YELLOW ) ;
697735 }
698736 }
699- // snap connections together
700737 if mouse_up {
701- // snap in a stable order
702- let mut conns: Vec < _ > = possible_connections. iter ( ) . collect ( ) ;
703- conns. sort_by_key ( |c| {
704- (
705- c. pin1 . pos . x . to_bits ( ) ,
706- c. pin1 . pos . y . to_bits ( ) ,
707- c. pin2 . pos . x . to_bits ( ) ,
708- c. pin2 . pos . y . to_bits ( ) ,
709- )
710- } ) ;
711- for conn in conns {
712- let instance = self . get_instance_mut ( conn. pin1 . ins ) ;
713- instance. move_pin ( conn. pin1 , conn. pin2 . pos ) ;
738+ for conn in & possible_connections {
739+ let ( pin1, pin2) = if let Some ( ( pin1, pin2) ) = conn. get_pin ( moving_instance_id)
740+ {
741+ ( pin1, pin2)
742+ } else {
743+ ( conn. pin1 , conn. pin2 )
744+ } ;
745+ let instance = self . get_instance ( pin1. ins ) ;
746+ if let InstanceType :: Wire ( _) = instance. ty {
747+ let wire = self . get_wire_mut ( instance. id ) ;
748+ if pin1. index == 0 {
749+ wire. start = pin2. pos ;
750+ } else {
751+ wire. end = pin2. pos ;
752+ } ;
753+ self . resize = None ;
754+ } else {
755+ let delta = { instance. move_pin_delta ( pin1, pin2. pos ) } ;
756+ self . mov_component_with_connected ( pin1. ins , delta, canvas_rect) ;
757+ }
714758 }
715- self . connections = possible_connections;
759+ for conn in & possible_connections {
760+ self . connections . insert ( * conn) ;
761+ }
762+ // Remove any connections not present in possible_connections
763+ self . connections
764+ . retain ( |conn| possible_connections. contains ( conn) ) ;
716765 }
717766 }
718767
@@ -863,6 +912,10 @@ impl TemplateApp {
863912 . expect ( "should not happen" )
864913 }
865914
915+ fn get_instance ( & self , id : InstanceId ) -> & Instance {
916+ self . instances . get ( id. usize ( ) ) . expect ( "should not happen" )
917+ }
918+
866919 fn get_connected_instances ( & self , id : InstanceId ) -> Vec < InstanceId > {
867920 let mut connecteds = Vec :: new ( ) ;
868921 let mut conns: Vec < _ > = self . connections . iter ( ) . collect ( ) ;
@@ -1019,3 +1072,35 @@ fn rotate_point(point: Pos2, origin: Pos2, angle: f32) -> Pos2 {
10191072
10201073 Pos2 :: new ( xnew + origin. x , ynew + origin. y )
10211074}
1075+
1076+ #[ cfg( test) ]
1077+ mod tests {
1078+ use super :: * ;
1079+
1080+ #[ test]
1081+ fn connection_normalization_and_hash_eq ( ) {
1082+ let a = Pin {
1083+ pos : pos2 ( 0.0 , 0.0 ) ,
1084+ ins : InstanceId ( 1 ) ,
1085+ index : 0 ,
1086+ } ;
1087+ let b = Pin {
1088+ pos : pos2 ( 10.0 , 0.0 ) ,
1089+ ins : InstanceId ( 2 ) ,
1090+ index : 1 ,
1091+ } ;
1092+
1093+ let c1 = Connection :: new ( a, b) ;
1094+ let c2 = Connection :: new ( b, a) ; // swapped
1095+
1096+ assert_eq ! ( c1, c2) ;
1097+
1098+ let mut set: HashSet < Connection > = HashSet :: new ( ) ;
1099+ let inserted1 = set. insert ( c1) ;
1100+ let inserted2 = set. insert ( c2) ;
1101+
1102+ assert ! ( inserted1) ;
1103+ assert ! ( !inserted2) ;
1104+ assert_eq ! ( set. len( ) , 1 ) ;
1105+ }
1106+ }
0 commit comments