1
$\begingroup$

I'm trying to write code to create a circuit from its connection information.
For example, in the image below you see an incompleted circuit with two batteries, one resistor and one capacitor. The position of two battery and ground connection is assumed to be fixed (on the left right side and bottom as in the image). However, the resistor and capacitor and switch can be placed in any position.

enter image description here

Also the nodes are marked with letters a, b, c, d, e, f, g as in the image.
Now assume that I have information such as:

  1. {"b","sw" "c"}: add a switch between node b and node c.
  2. {"d","wire" "e"}: add a wire between node d and node e.

So you would form a connection like this.

enter image description here

So if I have a connection input like this:

connection = {{"b", "sw", "c"}, {"d", "wire", "e"}, {"d", "sw", "a"}, {"f","wire", "g"}}

The expected output circuit would be something like this. The output circuit is not unique. It can be any shape but I'm looking for a method to make a good shape like this with no overlaping and looks nice.

enter image description here

Here is my current code:

The first part is some basic components from the previous post and with my ground[] function a

    resistor[l_ : 1, n_ : 3] := 
 Line[Table[{i l/(4 n), 1/3 Sin[i Pi/2]}, {i, 0, 4 n}]]

coil[l_ : 1, n_ : 3] := 
 Module[{scale = l/(5/16 n + 1/2), 
   pts = {{0, 0}, {0, 1}, {1/2, 1}, {1/2, 
      0}, {1/2, -1}, {5/16, -1}, {5/16, 0}}}, 
  Append[Table[
    BezierCurve[scale Map[{d 5/16, 0} + # &, pts]], {d, 0, n - 1}], 
   BezierCurve[scale Map[{5/16 n, 0} + # &, pts[[1 ;; 4]]]]]]

capacitor[l_ : 1] := {gap[l], 
  Line[l {{{1/3, -1}, {1/3, 1}}, {{2/3, -1}, {2/3, 1}}}]}

battery[l_ : 1] := {gap[
   l], {Rectangle[l {1/3, -(2/3)}, l {1/3 + 1/9, 2/3}], 
   Line[l {{2/3, -1}, {2/3, 1}}]}}

contact[l_ : 1] := {gap[l], 
  Map[{EdgeForm[Directive[Thick, Black]], FaceForm[White], 
     Disk[#, l/30]} &, l {{1/3, 0}, {2/3, 0}}]}

ground[l_ : 1] := {Line[l {{2/3, 0}, {1, 0}}], 
  Line[l {{2/3, -1}, {2/3, 1}}], Line[l {{1/3, -2/3}, {1/3, 2/3}}], 
  Line[l {{0, -1/3}, {0, 1/3}}]}

Options[display] = {Frame -> True, FrameTicks -> None, 
   PlotRange -> All, GridLines -> Automatic, 
   GridLinesStyle -> Directive[Orange, Dashed], 
   AspectRatio -> Automatic};
display[d_, opts : OptionsPattern[]] := 
 Graphics[Style[d, Thick], 
  Join[FilterRules[{opts}, Options[Graphics]], Options[display]]]

at[position_, angle_ : 0][obj_] := 
 GeometricTransformation[obj, 
  Composition[TranslationTransform[position], 
   RotationTransform[angle]]]

label[s_String, color_ : RGBColor[.3, .5, .8]] := 
  Text@Style[s, FontColor -> color, FontFamily -> "Geneva", 
    FontSize -> Large];

connect[pointList_] := {Line[pointList], 
  Map[Text[Style[
      "\!\(\*AdjustmentBox[\(\[Bullet]\),\n\
BoxBaselineShift->0.24615384615384617`,\nBoxMargins->{{0., 0.}, \
{-0.24615384615384617`, 0.24615384615384617`}}]\)", 
      FontSize -> 18], #] &, pointList[[{1, -1}]]]}

gap[l_ : 1] := Line[l {{{0, 0}, {1/3, 0}}, {{2/3, 0}, {1, 0}}}]

And this is my code to create the circuit:

    connection = {{"b", "sw", "c"}, {"d", "wire", "e"}, {"d", "sw", "a"}, {"f","wire", "g"}}
display[
     {battery[] // at[{0, 0}, Pi/2],
      battery[] // at[{8, 0}, Pi/2],
      ground[] // at[{0, -2}, Pi/2],
      connect[{{0, 0}, {0, -1}, {8, -1}, {8, 0}}],
      capacitor[] // at[{5, 2}, Pi/2],
      resistor[] // at[{2, 4}]}]

How can I create circuit from this with nice looking? Note that the connection input can be changed and would be nice to have a circuit still looks good with that changes.

Currently I'm stuck at insert a switch or a wire between two nodes and organize to form a nice shape.

$\endgroup$
2
  • 2
    $\begingroup$ This is a notoriously difficult problem. Type "schematic from netlist" to see what others have done in other languages. $\endgroup$
    – John Doty
    Commented Jan 19, 2022 at 22:03
  • $\begingroup$ @JohnDoty yeah, I hoped it is easier as in my circuit the two batteries and ground's positions are fixed. $\endgroup$
    – hana
    Commented Jan 19, 2022 at 22:05

1 Answer 1

4
$\begingroup$

Here is some code that should get you going.

The positions specify the left of the connection to the elements.

Clear["Global`*"]
con[pos1_, pos2_] := Line[{pos1, pos2}];(*connections*)
switch0[lab_ : 
    ""] := {Line[{{{0, 0}, {0.3, 0}, {0.7, 0.25}}, {{0.7, 0}, {1, 
       0}}}], Text[lab, {0.5, +0.3}]};
switchh[pos_, lab_ : ""] := (*horizontal switch*)
  switch0[lab] /. x : {_?NumericQ, _} :> pos + x;
switchv[pos_, lab_ : ""] := (*vertical switch*)
  Rotate[switch0[lab], Pi/2, {0, 0}] /. x : {_?NumericQ, _} :> pos + x;
res0[lab_ : 
    ""] := {Line[{{0, 0}, {0.1, 0}, {0.2, 0.3}, {0.4, -0.3}, {0.6, 
      0.3}, {0.8, -0.3}, {0.9, 0}, {1, 0}}], Text[lab, {0.5, +0.4}]};
resh[pos_, lab_ : ""] := res0 /. x : {_?NumericQ, _} :> pos + x; (*horizontal resistor*)
resv[pos_, lab_ : ""] := (*vertical resistor*)
  Rotate[res0[lab], Pi/2, {0, 0}] /. x : {_?NumericQ, _} :> pos + x;
cap0[lab_:""] := {Line[{{{0, 0}, {0.4, 0}}, {{0.4, -0.4}, {0.4, 
       0.4}}, {{0.6, -0.4}, {0.6, 0.4}}, {{0.6, 0}, {1, 0}}}], 
   Text[lab, {0.5, +0.5}]};
caph[pos_, lab_ : ""] := cap0[lab] /. x : {_?NumericQ, _} :> pos + x;
capv[pos_, lab_ : ""] := 
  Rotate[cap0[lab], Pi/2, {0, 0}] /. x : {_?NumericQ, _} :> pos + x;

And here is a short application:

Graphics[{
  con[{0, 0}, {1, 0}], switchh[{1, 0}, "switch 1"], con[{2, 0}, {3, 0}]
  , con[{3, 0}, {3, 1}], resv[{3, 1}, "resistor 1"], con[{3, 2}, {3, 3}]
  , con[{3, 3}, {2, 3}], caph[{1, 3}, "capacitor 1"], con[{1, 3}, {0, 3}]
  , con[{0, 3}, {0, 2}], resv[{0, 1}, "resistor 2"],  con[{0, 1}, {0, 0}]
}]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.