Рисование циферблата в Mathematica (в поисках лучшего решения) - PullRequest
10 голосов
/ 18 ноября 2011

Я пытаюсь найти общее решение для рисования циферблата, как графические объекты в Mathematica. Я уже реализовал собственную версию, но я думаю, что должно существовать гораздо лучшее решение. Буду признательна за более аккуратную версию с меньшим количеством кода или более четким мыслительным процессом.

Моя версия:

radius = 1;
elementList = 
  Join[Table[i, {i, 3, 1, -1}], Table[i, {i, 12, 4, -1}]];
elementNumber = Length[elementList];
thetaList = Table[i, {i, 0, 2 Pi, 2 Pi/elementNumber}][[1 ;; 12]];
coordinateList = Map[{radius*Cos[#], radius*Sin[#]} &, thetaList];
objectList = 
  Map[Style[#, FontFamily -> "Georgia", FontSize -> 30] &, 
   elementList];
Graphics[
 Join[
  MapThread[Text[#1, #2] &, {objectList, coordinateList}],
  {Circle[{0, 0}, 1.2*radius]}
  ]
 ]

enter image description here

Ответы [ 5 ]

11 голосов
/ 18 ноября 2011

Вот один из способов сделать часы:

clockFace = Import["http://i.imgur.com/ufanv.jpg"];
{hour, minute, second} = Take[Date[], -3];
hour = Mod[hour, 12] + minute/60.; 
Graphics3D[
{
 {Texture[clockFace], 
      Polygon[{{-1, -1, 0}, {1, -1, 0}, {1, 1, 0}, {-1, 1, 0}},
         VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}
      ]
 }, 
 {Black, AbsoluteThickness[8], 
      Line[{{0, 0, 0}, 
       .55 {Cos[Pi/2 - 2 Pi hour/12], Sin[Pi/2 - 2 Pi hour/12], 0}}
      ]
 },
 {Black, AbsoluteThickness[5], 
      Line[{{0, 0, 0}, 
       .8 {Cos[Pi/2 - 2 Pi minute/60], Sin[Pi/2 - 2 Pi minute/60], 0}}
      ]
 }
}, 
Boxed -> False, Lighting -> "Neutral"]

a clock with a nice face generated by Mathematica

Сложение

Вот вращающееся, вращающееся 3Dчасы для вашего развлечения:

clockFace = Import["http://i.imgur.com/ufanv.jpg"];
vtc = VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
hand[thickness_, radius_, time_] := {AbsoluteThickness[thickness],
   Line[{{0, 0, -1}, {radius Cos[Pi/2 + 2 Pi time],
      radius Sin[Pi/2 + 2 Pi time], -1}}],
   Line[{{0, 0, 1}, {radius Cos[Pi/2 - 2 Pi time],
      radius Sin[Pi/2 - 2 Pi time], 1}}],
   Line[{{0, -1, 0}, {radius Cos[Pi/2 - 2 Pi time], -1,
      radius Sin[Pi/2 - 2 Pi time]}}],
   Line[{{0, 1, 0}, {radius Cos[Pi/2 + 2 Pi time], 1,
      radius Sin[Pi/2 + 2 Pi time]}}],
   Line[{{-1, 0, 0}, {-1, radius Cos[Pi/2 + 2 Pi time],
      radius Sin[Pi/2 + 2 Pi time]}}],
   Line[{{1, 0, 0}, {1, radius Cos[Pi/2 - 2 Pi time],
      radius Sin[Pi/2 - 2 Pi time]}}]};
Dynamic[
  {hour, minute, second} = Take[Date[], -3];
  hour = Mod[hour, 12] + minute/60.;
  Graphics3D[{
    {Texture[clockFace],
     Polygon[{{1, -1, -1}, {-1, -1, -1}, {-1, 1, -1}, {1, 1, -1}},
      vtc],
     Polygon[{{-1, -1, 1}, {1, -1, 1}, {1, 1, 1}, {-1, 1, 1}}, vtc],
     Polygon[{{-1, 1, -1}, {-1, -1, -1}, {-1, -1, 1}, {-1, 1, 1}},
      vtc], Polygon[{{1, -1, -1}, {1, 1, -1}, {1, 1, 1}, {1, -1, 1}},
      vtc], Polygon[{{-1, -1, -1}, {1, -1, -1}, {1, -1, 1}, {-1, -1,
        1}}, vtc],
     Polygon[{{1, 1, -1}, {-1, 1, -1}, {-1, 1, 1}, {1, 1, 1}}, vtc]
     }, {Black,
     hand[8, .55, hour/12],
     hand[5, .8, minute/60],
     hand[3, .8, second/60]
     }
    },
   Boxed -> False, Lighting -> "Neutral",
   ViewPoint ->
    5 {Cos[2 Pi second/60], Sin[2 Pi second/60],
      Sin[2 Pi second/30]}, SphericalRegion -> True,
Background -> Black, ImageSize -> Full]] // Deploy

3D clock

6 голосов
/ 18 ноября 2011

Вот версия функции, которая обобщает генерацию циферблата, чтобы вы могли легко изменять стиль чисел, количество «часов» и радиус грани:

Options[clockFace] = {FontFamily -> "Georgia", FontSize -> 30};
clockFace[hours_Integer, radius_?NumericQ, opts : OptionsPattern[]] /;
   hours > 0 && Im[radius] == 0 && radius > 0 :=
 With[{range = Range[12]},
  With[{objects = 
        Style[#, 
          FilterRules[{opts}, Options[Style]] ~Join~ Options[clockFace]] & /@ range,
       thetas = Pi/2 - 2 Pi*range/hours},
  Graphics[Append[
     MapThread[Text[#1, {Cos[#2], Sin[#2]}] &, {objects, thetas}],
     Circle[radius*1.2]]]]]

Некоторые вещи - просто проблемы стиля Mathematica; например,

FilterRules[{opts}, Options[Style]] ~Join~ Options[clockFace]

- это просто способ передачи соответствующих необязательных аргументов в Style, при этом убедившись, что значения по умолчанию clockFace используются там, где это уместно, потому что Mathematica будет использовать первое применимое правило, найденное в списке правил ( а параметры функций - это просто списки правил). Я также использовал With для именования вещей, вот почему есть такое вложение; другие люди могут предпочесть использовать один Module. В любом случае, всегда лучше делать вещи локальными переменными, когда это возможно.

Самым большим изменением, однако, было создание списка чисел по порядку, используя Range, а затем корректировку определения thetas, чтобы все оказалось в нужном месте. Я думаю, что намного легче увидеть, что происходит, потому что знак минус означает, что вы двигаетесь по часовой стрелке, а смещение на Pi/2 дает понять, что вы начинаете с верхней части часов.

5 голосов
/ 27 сентября 2014

Mathematica имеет то, что называется ClockGauge встроенным. Возможности стилизации циферблата безграничны, как видно из документации. Голая версия выглядит так:

ClockGauge[]

Clock gauge

5 голосов
/ 19 ноября 2011

Ниже приведены рабочие 3D часы , созданные путем простого объединения ответа @ Арноуда с записью Кристофера в блоге :

makeHand[fl_, bl_, fw_, bw_] :=
    Polygon[{{-bw, -bl, 0.1}, {bw, -bl, 0.1}, {fw, fl, 0.1}, 
             {0, fl + 8 fw, 0.1}, {-fw, fl, 0.1}}/9];

hourHand = makeHand[5, 5/3, .1, .3];
minuteHand = makeHand[7, 7/3, .1, .3];
secondHand = {Red, EdgeForm[Black], makeHand[7, 7/3, .1/2, .3/2]};
clockFace = Import["http://i.imgur.com/ufanv.jpg"];

Graphics3D[{
  {Texture[clockFace], 
   Polygon[{{-1, -1, 0}, {1, -1, 0}, {1, 1, 0}, {-1, 1, 0}}, 
    VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]},

    Rotate[hourHand, Dynamic[Refresh[-30 Mod[AbsoluteTime[]/3600, 60] \[Degree], 
     UpdateInterval -> 60]], {0, 0, 1}],
    Rotate[minuteHand, Dynamic[Refresh[-6 Mod[AbsoluteTime[]/60, 60] \[Degree], 
     UpdateInterval -> 1]], {0, 0, 1}],
    Rotate[secondHand, Dynamic[Refresh[-6 Mod[AbsoluteTime[], 60] \[Degree], 
     UpdateInterval -> 1/20]], {0, 0, 1}]}, Boxed -> False]

enter image description here

Редактировать

Анимация была захвачена с помощью Rasterize [] внутри запланированного задания!

a = Graphics3D[(* etc etc*)];
b = {};
t = CreateScheduledTask[AppendTo[b, Rasterize@a], {2, 30}];
StartScheduledTask[t];
While[MatchQ[ScheduledTasks[], {ScheduledTaskObject[_, _, _, _,True]}],Pause[1]];
RemoveScheduledTask[ScheduledTasks[]];
Export["c:\\test.gif", b, "DisplayDurations" -> 1]
3 голосов
/ 19 ноября 2011

Ваш метод в порядке. Это просто немного грязно. Вот моя интерпретация:

hours = 12;
radius = 1;
thetaList = Rest@Range[2 Pi, 0, -2 Pi/hours] + Pi/2;
coordinateList = radius {Cos@#, Sin@#} & /@ thetaList;
Graphics[{
  FontFamily -> "Georgia",
  FontSize -> 30,
  Text ~MapThread~ {Range@hours, coordinateList},
  Circle[{0, 0}, 1.2 radius]
}]

same output

...