在Mathematica中绘制钟面(寻找更好的解决方案)

发布于 2024-12-16 16:58:40 字数 700 浏览 2 评论 0原文

我试图找到一个通用的解决方案,用于在 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]}
  ]
 ]

在此处输入图像描述

I am trying to find a general solution for drawing clock face like graphical objects in Mathematica. I've already implemented a version of my own, but I think a much better solution must exist. A neater version with less code or clearer thought process would be appreciated.

My version:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甜`诱少女 2024-12-23 16:58:40

这是制作时钟的一种方法:

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 beautiful 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 时钟

Here is one way to make a clock:

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

Addition

Here is a rotating, spinning 3D clock for your amusement:

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

牵你手 2024-12-23 16:58:40

这是一个函数的版本,它概括了钟面的生成,使您可以轻松更改数字的样式、“小时”的数量以及钟面的半径:

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 风格的问题;有些东西只是 Mathematica 风格的问题;例如,

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

这只是将相关可选参数传递给 Style 的方法,同时确保在相关的地方使用 clockFace 的默认值,因为 Mathematica 将使用第一个适用的值它在规则列表中找到的规则(函数选项只是规则列表)。我还使用 With 来命名事物,这就是为什么会有嵌套;其他人可能更喜欢使用单个模块。无论哪种方式,只要有可能,最好将事物设置为局部变量。

不过,最大的变化是使用 Range 按顺序生成数字列表,然后调整 thetas 的定义,以便一切都出现在正确的位置。我认为更容易看到正在发生的事情,因为减号意味着您正在顺时针移动,并且偏移 Pi/2 可以清楚地表明您是从时钟的顶部开始的。

Here's a version of a function that generalizes the generation of clock face to allow you to easily change the style of the numbers, the number of "hours", and the radius of the face:

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]]]]]

Some things are just Mathematica style issues; for instance,

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

is just the way to pass the relevant optional arguments to Style while making sure that clockFace's default values are used where relevant, because Mathematica will use the first applicable rule that it finds in a list of rules (and function options are just lists of rules). I also used With to name things, which is why there's that nesting; other people might prefer to use a single Module. Either way, it's always best to make things local variables whenever possible.

The biggest change, though, was generating the list of numbers in order, using Range, and then adjusting the definition of thetas so everything winds up in the right place. I think it's much easier to see what's going on, because the minus sign means you're moving around clockwise and offsetting by Pi/2 makes it clear you're starting at the top of the clock.

就是爱搞怪 2024-12-23 16:58:40

以下是通过将 @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]

在此处输入图像描述

编辑

动画是通过在计划任务中使用 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]

The following is a working 3D clock made by easily combining @Arnoud's answer with Christopher's blog entry:

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

The animation was captured by using Rasterize[] inside a scheduled task!

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]
年华零落成诗 2024-12-23 16:58:40

Mathematica has something called ClockGauge built-in. The possibilities for styling the clock face are endless, as can be seen in the documentation. The bare-bone version looks like this:

ClockGauge[]

Clock gauge

¢好甜 2024-12-23 16:58:40

你的方法很好。只是有点乱。这是我的解释:

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

Your method is fine. It is just a little messy. Here is my interpretation:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文