Рисование часов в Mathematica (поиск лучшего решения)
Я пытаюсь найти общее решение для рисования тактовой поверхности, как графические объекты в 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]()
Ответы
Ответ 1
Вот один из способов сделать часы:
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]()
Ответ 2
Здесь версия функции, которая обобщает генерацию циферблата, позволяет легко изменять стиль чисел, количество "часов" и радиус лица:
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
позволяет понять, что вы начинаете в верхней части часов.
Ответ 3
Ниже приведено рабочий 3D-такт, созданный путем простого объединения ответа @Arnoud с запись в блоге Christopher:
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]()
Edit
Анимация была захвачена с помощью Rasterize [] внутри запланированной задачи!
a = Graphics3D[(* etc etc*)];
b = {};
t = CreateScheduledTask[AppendTo[b, [email protected]], {2, 30}];
StartScheduledTask[t];
While[MatchQ[ScheduledTasks[], {ScheduledTaskObject[_, _, _, _,True]}],Pause[1]];
RemoveScheduledTask[ScheduledTasks[]];
Export["c:\\test.gif", b, "DisplayDurations" -> 1]
Ответ 4
В Mathematica есть что-то, называемое ClockGauge
. Возможности стилизации циферблата бесконечны, как видно из документации. Версия bare-bone выглядит следующим образом:
ClockGauge[]
![Clock gauge]()
Ответ 5
Ваш метод в порядке. Это просто немного грязно. Вот моя интерпретация:
hours = 12;
radius = 1;
thetaList = [email protected][2 Pi, 0, -2 Pi/hours] + Pi/2;
coordinateList = radius {[email protected]#, [email protected]#} & /@ thetaList;
Graphics[{
FontFamily -> "Georgia",
FontSize -> 30,
Text ~MapThread~ {[email protected], coordinateList},
Circle[{0, 0}, 1.2 radius]
}]
![same output]()