Re: Software that makes placemats
Posted: 13:00 Sat 03 Nov 2018
As requested:


A place for those passionate about port, and for those new to it. We hold lots of Port tastings: please join us!
https://www.theportforum.com/

/Alternating
/Sideways
/Upright
Code: Select all
/TastingNotesStarsNameColsRowsArrangement % (ASCIIfied Name) NumCols NumRows /Alternating|/Sideways|/Upright
[
(DRT) 5 1 /Upright (Derek T.) 4 copy pop
(WPS) 5 1 /Sideways (Wolfgang S.) 4 copy pop
(PW) 5 1 /Sideways (Phil W.) 4 copy pop
(DJ) 5 1 /Sideways (Daniel J.) 4 copy pop
(IDJ) 5 1 /Alternating (Ian J.) 4 copy pop
(DRL) 5 1 /Alternating (Dave L.) 4 copy pop
(TC) 5 1 /Alternating (Tony C.) 4 copy pop
(MPM) 5 1 /Alternating (Mike M.) 4 copy pop
] def % /TastingNotesStarsNameColsRowsArrangementCode: Select all
On Open
{
If Today ≤ HardWiredDateConstantBeingDateOfTasting
{
MessageBoxPopUp
string="This version HardWiredStringConstant: check that is latest with a force-reload."
Buttons={"OK, checked"}
}
}Code: Select all
(* PostScriptForm — this version of Jan 2019. *)
(* \
PostScriptForm[] *)
(*
\
http://mathematica.stackexchange.com/questions/101954/postscriptform-\
or-forthform
http://mathematica.stackexchange.com/questions/102894/multi-case-\
function-many-single-case-delayed-assignments-or-one-which
*)
Remove[PostScriptForm];
PostScriptForm[thing_Rational] :=
If[Abs[Denominator[
thing]/(2^IntegerExponent[Denominator[thing], 2])/(5^
IntegerExponent[Denominator[thing], 5])] == 1,
ToString[N[thing, 20], InputForm, NumberMarks -> False],
PostScriptForm[Numerator[thing]] <> " " <>
PostScriptForm[Denominator[thing]] <> " div"];
PostScriptForm[thing_?AtomQ] := ToString[thing];
PostScriptForm[thing_List] :=
StringJoin @@ Riffle[Map[PostScriptForm, thing], "\r\n"];
PostScriptForm[MatrixForm[thing_]] := PostScriptForm[thing];
PostScriptForm[Times[-1, thing_]] :=
StringJoin[PostScriptForm[thing], " neg"];
PostScriptForm[thing_Power] := (
psExponent := Which[
# > 5 && Divisible[#, 3],
psExponent[#/3] <> " dup dup mul mul",
# >= 5 && OddQ[#],
"dup " <> psExponent[(# - 1)/2] <> " dup mul mul" ,
# >= 4 && EvenQ[#], psExponent[#/2] <> " dup mul",
# == 3, "dup dup mul mul",
# == 2, "dup mul",
# == 1/2, "sqrt",
# == 3/2, "dup sqrt mul",
# < 0, psExponent[-#] <> " 1 exch div",
(Rational === Head[#]) && (Log[2, # // Denominator] //
IntegerQ), psExponent[Simplify[2 #]] <> " sqrt",
Not[IntegerQ[#]], PostScriptForm[#] <> " exp",
# == 1, "",
True,
" !!!\[Bullet]\[Bullet]\[Bullet]Error with exponent = " <>
ToString[#] <> "\[Bullet]\[Bullet]\[Bullet]!!! "
] &;
Which[
thing[[2]] > 0 || Not[IntegerQ[thing[[2]]]],
PostScriptForm[thing[[1]]] <> " " <> psExponent[thing[[2]]],
thing[[2]] == -1, "1 " <> PostScriptForm[thing[[1]]] <> " div",
thing[[2]] == 0, "1",
True,
"1 " <> PostScriptForm[thing[[1]]] <> " " <>
psExponent[-thing[[2]]] <> " div"
]);
PostScriptForm[thing_Times] :=
StringJoin@
Riffle[Reap[
If[MatchQ[thing[[1]],
Power[_,
n_Integer /; n < 0]], (Sow[
"1 " <> PostScriptForm[thing[[1, 1]]] <> " div"];), (Sow[
PostScriptForm[thing[[1]]]];)];
Map[(If[MatchQ[#,
Power[_,
n_Integer /; n < 0]], (Sow[
PostScriptForm[#[[1]]^(-#[[2]])] <> " div"];), (Sow[
PostScriptForm[#] <> " mul"]; )]) &,
Drop[List @@ thing, 1]]][[2, 1]], " "];
PostScriptForm[thing_Plus] :=
StringJoin @@ If[FreeQ[thing, _^n_],
(* Simple expression, no powers,
to be summed one item at a time *)
Module[{i},
i =
Position[thing, Except[Times[-1, _] | (_?Negative)], 1,
Heads -> False];
If[Length[i] > 0,
i = i[[1, 1]], (i =
Position[thing, Not[MatchQ[#, Times[-1, _]]] &, 1,
Heads -> False]; i = If[Length[i] > 0, i[[1, 1]], 1])];
Prepend[
Map[(" " <>
Replace[#, {(n_Integer /; n < 0 :>
ToString[-n] <> " sub"), (Times[-1, _] :>
PostScriptForm[Times @@ Drop[#, 1]] <> " sub"), (Times[
n_ /; n < 0, _] :>
PostScriptForm[Times @@ Drop[#, 1]] <> " " <>
ToString[-#[[1]]] <> " mul sub"), (Times[
n_ /; n > 0, _] :>
PostScriptForm[Times @@ Drop[#, 1]] <> " " <>
ToString[#[[1]]] <> " mul add"), (_ :>
PostScriptForm[#] <> " add")}]) &,
Drop[List @@ thing, {i}]],
Replace[thing[[
i]], {Times[-1, _] :>
PostScriptForm[-thing[[i]]] <> " neg", _ :>
PostScriptForm[thing[[i]]]}]] ],
(* Polynomial *)
Module[{vars, exps, v, rcl, i, firstMul},
vars = Variables[thing];
exps = Exponent[thing, vars];
v =
Select[Transpose[{vars, exps}], (#[[2]] == Max @@ exps) &][[1,
1]];
rcl = Reverse[Map[Factor, CoefficientList[thing, v]]];
Reap[
i = 1; firstMul = True;
If[rcl[[1]] =!= 1, Sow[PostScriptForm[rcl[[1]]]]];
Map[
If[# === 0,
i++, (Sow[
If[firstMul && rcl[[1]] === 1, PostScriptForm[v^i] <> " ",
" " <> PostScriptForm[v^i] <> " mul "] <>
If[MatchQ[#, (Times[_?Negative, _] | (_?Negative))],
PostScriptForm[-#] <> " sub",
PostScriptForm[#] <> " add"]]; i = 1;
firstMul = False)] &, Drop[rcl, 1]];
If[i > 1, Sow[" " <> PostScriptForm[v^(i - 1)] <> " mul "]];
][[2, 1]]
]];Code: Select all
circlepos = {{1, 1, 1}, {1, 2, -1}, {2, 1, 1}, {2, 2, -1}};
p1 = ListPlot[circlepos, PlotRange -> {{0, 3}, {0, 3}}];
pot[x_, y_, qx_, qy_, q_] := q/Sqrt[(x - qx)^2 + (y - qy)^2]
potgridx[x_, y_] =
D[Total[Table[
pot[x, y, circlepos[[i, 1]], circlepos[[i, 2]],
circlepos[[i, 3]]], {i, 1, Length[circlepos]}]], x];
potgridy[x_, y_] =
D[Total[Table[
pot[x, y, circlepos[[i, 1]], circlepos[[i, 2]],
circlepos[[i, 3]]], {i, 1, Length[circlepos]}]], y];
p2 = StreamPlot[{potgridx[x, y], potgridy[x, y]}, {x, 0, 2.5}, {y, 0,
2.5}];
Show[p1, p2]Yes. Converts basic expressions to (slightly) idiomatic PostScript. Typical use case is a polynomial to be solved: it converts the CoefficientList, which is then passed to a PostScript polynomial solver.
Code: Select all
circlepos = {
{0, 1, 1},
{Sqrt[3.]/2, 0.5, -1},
{Sqrt[3.]/2, -0.5, 1},
{0, -1, -1},
{-Sqrt[3.]/2, -0.5, 1},
{-Sqrt[3.]/2, 0.5, -1},
{0, 0, 1}
};Love it.
Fixed.jdaw1 wrote: ↑20:04 Mon 17 Jun 2019
Your approach is well suited to circles in a rectangular grid. Not so much in a hexagonal grid. E.g.:Code: Select all
circlepos = { {0, 1, 1}, {Sqrt[3.]/2, 0.5, -1}, {Sqrt[3.]/2, -0.5, 1}, {0, -1, -1}, {-Sqrt[3.]/2, -0.5, 1}, {-Sqrt[3.]/2, 0.5, -1}, {0, 0, 1} };
Code: Select all
circlevec = {{0, 1, 1}, {Sqrt[3.]/2, 0.5, -1}, {Sqrt[3.]/2, -0.5,
1}, {0, -1, -1}, {-Sqrt[3.]/2, -0.5, 1}, {-Sqrt[3.]/2,
0.5, -1}, {0, 0, 1}};
circlepos =
Table[{circlevec[[i, 1]], circlevec[[i, 2]]}, {i, 1,
Length[circlevec]}];
p1 = ListPlot[circlepos, PlotRange -> {{-2.5, 2.5}, {-2.5, 2.5}},
PlotMarkers -> {Automatic, Large}];
pot[x_, y_, qx_, qy_, q_] := q/Sqrt[(x - qx)^2 + (y - qy)^2]
potgridx[x_, y_] =
D[Total[Table[
pot[x, y, circlevec[[i, 1]], circlevec[[i, 2]],
circlevec[[i, 3]]], {i, 1, Length[circlevec]}]], x];
potgridy[x_, y_] =
D[Total[Table[
pot[x, y, circlevec[[i, 1]], circlevec[[i, 2]],
circlevec[[i, 3]]], {i, 1, Length[circlevec]}]], y];
p2 = StreamPlot[{potgridx[x, y], potgridy[x, y]}, {x, -2.5,
2.5}, {y, -2.5, 2.5}];
Show[p1, p2]So do I, but perhaps more for its wilful stubbornness than its practicality.
Hmm. Bug or feature?






Ok, I will try zeroing at 2^-23.
Code: Select all
ContourPlot[
Log[Total[
Table[pot[x, y, circlevec[[i, 1]], circlevec[[i, 2]],
circlevec[[i, 3]]], {i, 1, Length[circlevec]}]]], {x, -2.5,
2.5}, {y, -2.5, 2.5}, Contours -> 20]From the imagery, would I be correct in thinking that each point represents a certain positive or negative charge, and therefore that the reason some points connect to others while others pairs to not is that essentially we are only seeing lines between points of opposite (or different) charge? If so, some variation from binary charge setting would enable alternate maps with all points connecting, though would be potentially difficult to keep regular and symmetrical for all designs without specific rules.
Good idea. I also changed circlepos to a different hexagonal lattice..PhilW wrote: ↑07:20 Tue 18 Jun 2019 From the imagery, would I be correct in thinking that each point represents a certain positive or negative charge, and therefore that the reason some points connect to others while others pairs to not is that essentially we are only seeing lines between points of opposite (or different) charge? If so, some variation from binary charge setting would enable alternate maps with all points connecting, though would be potentially difficult to keep regular and symmetrical for all designs without specific rules.
Based on the above, but varying slightly, would making the centre of all circles could be a positive charge, and then placing negative charges between (either in the spaces or the mid-point between adjacent circles) might provide a more fully-connected and symmetric output, though I can't picture whether that might become too linear.
Code: Select all
{{0, 2 Sqrt[2], -1}, {Sqrt[2], Sqrt[2], -1}, {-Sqrt[2],
Sqrt[2], -1}, {0, -2 Sqrt[2], -1}, {-Sqrt[2], -Sqrt[2], -1}, {Sqrt[
2], -Sqrt[2], -1}, {0, 0, 1}}Charges good. Because circles touch, hexagonal was better.
For this type of layout, might a triangle tesselation with charges {⅓,⅔,1} be correct?
Code: Select all
circlevec = {
{0, 1, 1},
{Sqrt[3.]/2, 0.5, 1/3},
{Sqrt[3.]/2, -0.5, 1},
{0, -1, 1/3},
{-Sqrt[3.]/2, -0.5, 1},
{-Sqrt[3.]/2, 0.5, 1/3},
{0, 0, 2/3}
};
p1 = Map[Graphics[{Red, Thick, Circle[{#[[1]], #[[2]]}, 0.5]}] &, circlevec[[All, 1 ;; 2]]];
pot[x_, y_, qx_, qy_, q_] := q/Sqrt[(x - qx)^2 + (y - qy)^2];
potgridx[x_, y_] =
D[Total[Table[
pot[x, y, circlevec[[i, 1]], circlevec[[i, 2]],
circlevec[[i, 3]]], {i, 1, Length[circlevec]}]], x];
potgridy[x_, y_] =
D[Total[Table[
pot[x, y, circlevec[[i, 1]], circlevec[[i, 2]],
circlevec[[i, 3]]], {i, 1, Length[circlevec]}]], y];
p2 = StreamPlot[{potgridx[x, y], potgridy[x, y]}, {x, -1.6,
1.6}, {y, -1.6, 1.6}];
Show[p1, p2, AspectRatio -> 1]
I never said it was an efficient packing
I am absolutely sure it will be very tricky.
Or choose seed points in a small circle around a charge, perhaps every 15°. Flow uphill. But those won’t arrive at even angles at other charges, nor at even distances at edge. Then what? I don’t know.
Test implementation of the charge assignment: output looks good — nearby circles have different charges; PostScript code follows.jdaw1 wrote: ↑22:17 Tue 18 Jun 2019Possible algorithm for assigning charges
Circles either have a charge assigned (hurray!), which is one of {1,2,3}. Or don’t yet, in which case deemed charge is 0.
Repeatedly we’ll compute, for circle i, Poti0, Poti1, Poti2, and Poti3.
Potik ≡ ∑j ( (xi − xj)² + (yi − yj)² )⁻¹ where j≠i and circle j has charge k.
Pick of the i with no assigned charge the largest value of Poti0÷1024 + Poti1 + Poti2 + Poti3
Assign to it the the charge {3,1,2} according to whichever is smallest of Poti3, Poti1, Poti2, with ties being resolved in that order.
Repeat until all charges assigned.
Code: Select all
/ParametersVersionDateTimeAdobeFormat (D:201906202330) def
/Circlearrays [ [/lozenge] 15 {dup} repeat pop ] def
/Titles [ ( ) 15 {dup} repeat pop ] def
/Belowtitles [ Titles length {()} repeat ] def
/Names [
(JDAW)
] def
/HeadersLeft [
0 [(Assigning charges: a test)]
] def % /HeadersLeft
/HeadersCenter [
] def % /HeadersCenter
/HeadersRight [
0
{ExternalLinks 2 get}
] def % /HeadersRight
/ExternalLinks [ % Array, length a multiple of three: indented0-boolean, (Descriptor0), (http://URL0), indented1-boolean, (Descriptor1), (http://URL1), ...
false (Thread on ThePortForum.com) (http://www.theportforum.com/viewtopic.php?t=175&start=1136#p112232)
false (Algorithm on ThePortForum.com) (http://www.theportforum.com/viewtopic.php?p=112250#p112250)
false (Latest version this placemat) (http://www.jdawiseman.com/papers/2019/20190620_Charges.pdf)
] def % /ExternalLinks
/VoteRecorders false def
/CorkDisplayNumCopies 0 def
/NeckTagsNumCopies 0 def
/DecantingNotesNumCopies 0 def
/TastingNotePagesNumCopies 0 def
/PaperType { [ /A3 /A4 dup dup dup /A3 dup dup dup] SheetNum get } def
/Orientation {SheetNum 1 eq SheetNum 2 eq or {/Portrait} {/Landscape} ifelse} def % /Landscape /Portrait
/GlassesOnSheets [
[ 7 5 6 5 7 11 13 14 15 ]
{ [ exch 0 exch 1 exch 1 sub {} for ] }
forall
] def % /GlassesOnSheets
/ShrinkRadii /NotAtAll def % /NotAtAll | /ToSmallest | /ToSmallestSamePageOrdering | array denoting equivalence classes
/PackingStyles [
[ /RectangularDislocation /OnlyIfSheetNumMin 1 ]
[ /Diamonds /OnlyIfSheetNumMin 1 ]
[ /DiamondsAndRectangular /OnlyIfSheetNumMin 1 ]
[ /Bespoke5 /OnlyIfOrientation /Landscape /OnlyIfSheetNumMin 1 ]
[ /Bespoke7 /OnlyIfOrientation /Landscape/OnlyIfSheetNumMin 1 ]
[ /RectangularAlternateSplitNudge /OnlyIfSheetNumMin 1 /ImprovementPointsMin 2 ]
[ /DiamondsPlus /OnlyIfOrientation /Portrait /OnlyIfSheetNumMin 1 ]
[ /DiamondsPlus /OnlyIfOrientation /Landscape /OnlyIfSheetNumMin 1 /ImprovementPointsMin 2 ]
[ /RectangularAlternateNudge /OnlyIfSheetNumMin 1 /ImprovementPointsMin 2 ]
[ /Arch /CentralGlasses 1 /GlassesNumMin 6 /OnlyIfOrientation /Landscape ]
] def % /PackingStyles
/PaintBackgroundCode
{
% Done properly, the computations would be in PrologueCode, and only the painting in PaintBackgroundCode.
/Glasses TypeOfPagesBeingRendered eq
{
10 dict begin
/N1s GlassPositions SheetNum get length 1 sub def
/Xs [ GlassPositions SheetNum get {0 get} forall ] def
/Ys [ GlassPositions SheetNum get {1 get} forall ] def
/Charges [ 0 N1s {dup} repeat ] def
/Title 1 string def Title 0 65 put
N1s 1 add
{
/Pot [ 4 { [ 0 N1s {dup} repeat ] } repeat ] def
0 1 N1s
{
/i exch def
0 1 N1s
{
/j exch def
i j ne
{
Pot Charges j get get i 2 copy get 1 Xs i get Xs j get sub dup mul Ys i get Ys j get sub dup mul add div add put
} if % i j ne
} for % j
} for % i
/PotMax -1 def
/iBest -1 def
0 1 N1s
{
/i exch def
Charges i get 0 eq
{
Pot 0 get i get 1024 div Pot 1 get i get add Pot 2 get i get add Pot 3 get i get add
dup PotMax gt {/PotMax exch def /iBest i def} {pop} ifelse
} if % Charges i get 0 eq
} for % i
Charges iBest
Pot 3 get iBest get Pot 1 get iBest get le
{Pot 3 get iBest get Pot 2 get iBest get le {3} {2} ifelse}
{Pot 1 get iBest get Pot 2 get iBest get le {1} {2} ifelse}
ifelse put
TitlesFont RadiiCirclearrayInside SheetNum get 1.9 mul selectfont
GlassPositions SheetNum get iBest get aload pop moveto
GSave nulldevice 0 0 moveto Title false CharPathRecursive PathBBox GRestore exch 4 -1 roll add -2 div 3 1 roll add -2 div rmoveto
[ {/Error} {0.8 setgray} {0.4 0.4 0.5 setrgbcolor} {0.6 0 0 setrgbcolor} ] Charges iBest get get exec
Title ShowRecursive
Title 0 2 copy get 1 add put
} repeat
end
} if
} bind defCode: Select all
h = 297 (360/127) - 30 - 24;
w = 210 (360/127) - 24 - 24;
r = w/4;
Clear["yy"]; yy = yy /. Solve[(yy - r)^2 == (h - r - yy)^2 + (w/2 - r)^2, yy][[1]];
Print["h=", h, " w=", w, " r=", r, " yy=", yy];
Print[N[circlevec = {
{w/2, h - r, 2},
{r, yy, 3},
{w - r, yy, 1},
{r, r, 2},
{w - r, r, 3}
}] // MatrixForm];
p1 = Map[Graphics[{Red, Thick, Circle[{#[[1]], #[[2]]}, r]}] &, circlevec[[All, 1 ;; 2]]];
p2 = Graphics[Map[Text[Style[#[[3]], FontSize -> 60, Bold, Green], {#[[1]], #[[2]]}, {0, 0}] &, circlevec]];
pot[x_, y_, qx_, qy_, q_] := q/Sqrt[(x - qx)^2 + (y - qy)^2];
potgridx[x_, y_] = D[Total[Table[pot[x, y, circlevec[[i, 1]], circlevec[[i, 2]], circlevec[[i, 3]]], {i, 1, Length[circlevec]}]], x];
potgridy[x_, y_] = D[Total[Table[pot[x, y, circlevec[[i, 1]], circlevec[[i, 2]], circlevec[[i, 3]]], {i, 1, Length[circlevec]}]], y];
p3 = StreamPlot[{potgridx[x, y], potgridy[x, y]}, {x, 0, w}, {y, 0, h}];
Show[p1, p2, p3, AspectRatio -> h/w]
Do you have a pseudo-code algorithm?If only StreamPlot weren’t so fiercely difficult to re-code.
Interesting. I will test. Might the mesh of points be too fine — points too close — such that it loses the macro structure?PhilW wrote: ↑20:23 Sun 23 Jun 2019A suggestion for alternate charge-plan to try and regularise:
- For every circle, inscribe a hexagon (possibly slightly smaller diameter).
- Assign charge to hexagon points (instead of circle centres), all with +1 at top point, then alternating -1/+1 around the hexagon.
In any square or hexagonal arrangement of circles, that should avoid like charges bring close, allowing good connectivity between, while also being regular/simple charge definition for all layouts.
No.
My gut feel was that it should be viable for hexagons, but that moving to decagons or higher 2*oddN sided polygons would be too fine. Might/not work, but thought worth suggesting to try.jdaw1 wrote:Interesting. I will test. Might the mesh of points be too fine — points too close — such that it loses the macro structure?
Code: Select all
h = 297 (360/127) - 30 - 24;
w = 210 (360/127) - 24 - 24;
r = w/4;
Clear["yy"]; yy =
yy /. Solve[(yy - r)^2 == (h - r - yy)^2 + (w/2 - r)^2, yy][[1]];
Print["h=", h, " w=", w, " r=", r, " yy=", yy];
Print[N[circleCentres = {
{w/2, h - r},
{r, yy},
{w - r, yy},
{r, r},
{w - r, r}
}] // MatrixForm];
p1 = Map[Graphics[{Red, Thick, Circle[{#[[1]], #[[2]]}, r]}] &,
circleCentres];
charges = Flatten[Map[{
{#[[1]], #[[2]] + r, +1},
{#[[1]] + r Sqrt[3]/2, #[[2]] + r/2, -1},
{#[[1]] + r Sqrt[3]/2, #[[2]] - r/2, +1},
{#[[1]], #[[2]] - r, -1},
{#[[1]] - r Sqrt[3]/2, #[[2]] - r/2, +1},
{#[[1]] - r Sqrt[3]/2, #[[2]] + r/2, -1}
} &, circleCentres], 1];
p2 = Map[Graphics[{Green, Thick, Circle[{#[[1]], #[[2]]}, r/48]}] &,
charges];
pot[x_, y_, qx_, qy_, q_] := q/Sqrt[(x - qx)^2 + (y - qy)^2];
potgridx[x_, y_] =
D[Total[Table[
pot[x, y, charges[[i, 1]], charges[[i, 2]], charges[[i, 3]]], {i,
1, Length[charges]}]], x];
potgridy[x_, y_] =
D[Total[Table[
pot[x, y, charges[[i, 1]], charges[[i, 2]], charges[[i, 3]]], {i,
1, Length[charges]}]], y];
p3 = StreamPlot[{potgridx[x, y], potgridy[x, y]}, {x, 0, w}, {y, 0,
h}];
Show[p1, p2, p3, AspectRatio -> h/w]
Code: Select all
h = 297 (360/127) - 30 - 24;
w = 210 (360/127) - 24 - 24;
r = w/4;
Clear["yy"]; yy =
yy /. Solve[(yy - r)^2 == (h - r - yy)^2 + (w/2 - r)^2, yy][[1]];
Print["h=", h, " w=", w, " r=", r, " yy=", yy];
Print[N[circleCentres = {
{w/2, h - r},
{r, yy},
{w - r, yy},
{r, r},
{w - r, r}
}] // MatrixForm];
p1 = Map[Graphics[{Red, Thick, Circle[{#[[1]], #[[2]]}, r]}] &,
circleCentres];
charges = Flatten[Map[{
{#[[1]], #[[2]] + r, +1},
{#[[1]] + r, #[[2]], -1},
{#[[1]], #[[2]] - r, +1},
{#[[1]] - r, #[[2]], -1}
} &, circleCentres], 1];
p2 = Map[Graphics[{Green, Thick, Circle[{#[[1]], #[[2]]}, r/48]}] &,
charges];
pot[x_, y_, qx_, qy_, q_] := q/Sqrt[(x - qx)^2 + (y - qy)^2];
potgridx[x_, y_] =
D[Total[Table[
pot[x, y, charges[[i, 1]], charges[[i, 2]], charges[[i, 3]]], {i,
1, Length[charges]}]], x];
potgridy[x_, y_] =
D[Total[Table[
pot[x, y, charges[[i, 1]], charges[[i, 2]], charges[[i, 3]]], {i,
1, Length[charges]}]], y];
p3 = StreamPlot[{potgridx[x, y], potgridy[x, y]}, {x, 0, w}, {y, 0,
h}];
Show[p1, p2, p3, AspectRatio -> h/w]
{Shudder} Translating that to PostScript would likely as not be 3k lines. {Shudder}akzy wrote: ↑16:34 Wed 26 Jun 2019Are you able to implement python in postscript? If so matplotlib has the stream plot coded out for you https://github.com/matplotlib/matplotli ... eamplot.py
Another option is manually translate into whatever language.
.nb
Code: Select all
h = 297 (360/127) - 30 - 24;
w = 210 (360/127) - 24 - 24;
r = w/4;
rr = 0.85 r;
Clear["yy"]; yy =
yy /. Solve[(yy - r)^2 == (h - r - yy)^2 + (w/2 - r)^2, yy][[1]];
Print["h=", h, " w=", w, " r=", r, " yy=", yy];
Print[N[circleCentres = {
{w/2, h - r},
{r, yy},
{w - r, yy},
{r, r},
{w - r, r}
}] // MatrixForm];
p1 = Map[Graphics[{Red, Thick, Circle[{#[[1]], #[[2]]}, r]}] &,
circleCentres];
charges = Flatten[Map[{
{#[[1]] , #[[2]] + rr, +1},
{#[[1]] + rr Sqrt[3]/2, #[[2]] + rr/2, -1},
{#[[1]] + rr Sqrt[3]/2, #[[2]] - rr/2, +1},
{#[[1]] , #[[2]] - rr, -1},
{#[[1]] - rr Sqrt[3]/2, #[[2]] - rr/2, +1},
{#[[1]] - rr Sqrt[3]/2, #[[2]] + rr/2, -1}
} &, circleCentres], 1];
p2 = Map[Graphics[{Green, Thick, Circle[{#[[1]], #[[2]]}, r/48]}] &, charges];
pot[x_, y_, qx_, qy_, q_] := q/Sqrt[(x - qx)^2 + (y - qy)^2];
potgridx[x_, y_] = D[Total[Table[pot[x, y, charges[[i, 1]], charges[[i, 2]], charges[[i, 3]]], {i,1, Length[charges]}]], x];
potgridy[x_, y_] = D[Total[Table[pot[x, y, charges[[i, 1]], charges[[i, 2]],charges[[i, 3]]], {i, 1, Length[charges]}]], y];
p3 = StreamPlot[{potgridx[x, y], potgridy[x, y]}, {x, 0, w}, {y, 0, h}];
Show[p1, p2, p3, AspectRatio -> h/w]
Why? The inward pointing of the lines, the sitting in its own gravitational well, has the outside pointing to the important stuff — the juice. Within which I like the visual interest of not having macro symmetry. And the fewness of the lines hides the micro structure of 6× as many charges.
I agree with the preference, because of the inward/outward pointing of the lines, though I would also prefer macro symmetry; I was hoping to achieve the former with the regular hexagon plan by moving the charges further inside, but alas that doesn't seem sufficient.jdaw1 wrote: ↑22:56 Fri 28 Jun 2019I prefer:Why? The inward pointing of the lines, the sitting in its own gravitational well, has the outside pointing to the important stuff — the juice. Within which I like the visual interest of not having macro symmetry. And the fewness of the lines hides the micro structure of 6× as many charges.
First (.nb) has shuffled charges, integers from half the number of glasses to 1½× that.PhilW wrote: ↑05:46 Sat 29 Jun 2019I agree with the preference, because of the inward/outward pointing of the lines, though I would also prefer macro symmetry; I was hoping to achieve the former with the regular hexagon plan by moving the charges further inside, but alas that doesn't seem sufficient.
Code: Select all
h = 297 (360/127) - 30 - 24;
w = 210 (360/127) - 24 - 24;
r = w/4;
Clear["yy"]; yy = yy /. Solve[(yy - r)^2 == (h - r - yy)^2 + (w/2 - r)^2, yy][[1]];
Print["h=", h, " w=", w, " r=", r, " yy=", yy];
Print[N[circleCentres = {
{w/2, h - r},
{r, yy},
{w - r, yy},
{r, r},
{w - r, r}
}] // MatrixForm];
charges = Transpose[Join[Transpose[circleCentres], {RandomSample[Floor[Length[circleCentres]/2] + Range[Length[circleCentres]]]}]];
p1 = Map[Graphics[{Red, Thick, Circle[{#[[1]], #[[2]]}, r]}] &, circleCentres];
p2 = Graphics[ Map[Text[Style[#[[3]], FontSize -> 60, Bold, Green], {#[[1]], #[[2]]}, {0, 0}] &, charges]];
pot[x_, y_, qx_, qy_, q_] := q/Sqrt[(x - qx)^2 + (y - qy)^2];
potgridx[x_, y_] = D[Total[Table[pot[x, y, charges[[i, 1]], charges[[i, 2]], charges[[i, 3]]], {i, 1, Length[charges]}]], x];
potgridy[x_, y_] = D[Total[Table[pot[x, y, charges[[i, 1]], charges[[i, 2]], charges[[i, 3]]], {i, 1, Length[charges]}]], y];
p3 = StreamPlot[{potgridx[x, y], potgridy[x, y]}, {x, 0, w}, {y, 0, h}];
Show[p1, p2, p3, AspectRatio -> h/w]

This builds a StreamPlot from a low-resolution two-dimensional array. Ouch. Looking for an algorithm to which takes a function, the function taking (x, y) and returning the potential and appropriate derivatives.jdaw1 wrote: ↑22:17 Thu 27 Jun 2019{Shudder} Translating that to PostScript would likely as not be 3k lines. {Shudder}akzy wrote: ↑16:34 Wed 26 Jun 2019Are you able to implement python in postscript? If so matplotlib has the stream plot coded out for you https://github.com/matplotlib/matplotli ... eamplot.py
Another option is manually translate into whatever language.
This, I reckon, is going to be significantly harder. I will keep having a look around - there surely is some open source version of it somewhere (haven't had the proper chance to look into the paper you linked yet).jdaw1 wrote: ↑09:13 Sat 29 Jun 2019This builds a StreamPlot from a low-resolution two-dimensional array. Ouch. Looking for an algorithm to which takes a function, the function taking (x, y) and returning the potential and appropriate derivatives.jdaw1 wrote: ↑22:17 Thu 27 Jun 2019{Shudder} Translating that to PostScript would likely as not be 3k lines. {Shudder}akzy wrote: ↑16:34 Wed 26 Jun 2019Are you able to implement python in postscript? If so matplotlib has the stream plot coded out for you https://github.com/matplotlib/matplotli ... eamplot.py
Another option is manually translate into whatever language.
Note to self: Rainer Wegenkittl and Eduard Gröller.
Providing your postscript code is fine with calculating potgrid analytically (I have no idea how your conversion tool will deal with the mathematica analytical methods of processing functions) then its just an evaluate, advance, re-evaluate.akzy wrote: ↑17:05 Wed 19 Jun 2019 1. Create field seed spots at the edges of the circles (at whatever density we decide).
2. At that point, we have a vector (from potgridx and potgridy) telling us where the field goes next.
3. Follow that on some small distance (there is definitely a mathematical way of determining how small this distance is - I cant' remember however).
4. Return back to step 2 until you're off the mat or in another circle.
5. Fit a curve to each trace.
The darkness of this droplet should be normalised by, for a vector (potgridx and potgridy being the vector in question here) v=(x,y), |v|.
The size of the step should be normalised by the size of the vector to a first order (i.e.|v|) and the absolute of the first spatial derivative (i.e. |grad(v)|) to a second order. I think for this situation, the latter is the best option. As we already have potgrid calculated analytically, grad(potgrid) can also be calculated analytically, so I believe numerically calculating the second spatial derivative will not be required.
Sorry: hapy to acknowledge your prior art, and my slowness of understanding.
It can.
Yes.
But then it’ll be intense black near charges, and pale grey away. I want a more even grey tone across the page.
You’re colouring by intensity of slope — i.e., dark near charges. But I want to choose step size by inverse curvature to lessen the number of “evaluate, advance, re-evaluate” steps. I suspect this will need ∇v.
How? More of a curiosity thing than anything. Differentiating analytically using a computer is something I never fully understood (I'm still convinced that wolfram works using magic). If you know of any good explanations (or fancy trying yourself) please send them my way.
My sneaky trick for all of these problems is to whack a logarithm on it somewhere. I had this exact problem trying to produce an electric field graphic for a paper - make the function logarithmic and everything looks better
I agree - ∇v is the way to do it. Higher orders wont help. The question is, what stepsize will it normalise? I think your 2pt idea seems to be a good plan followed by your interpolation of choice.
Hmmm. No idea.