1
$\begingroup$

I wrote the following code as an example of my question:

 Manipulate[
 Graphics[{
   Red, Rectangle[{0, 0}, {5, 5}],
   Blue, Translate[Disk[{1, 1}, 1], {8 cross, 1}],
   Green, Rectangle[{5, 5}, {10, 0}]}
  , PlotRange -> All]
 , {cross, 0, 1}]

I would like to move the blue disk over the red rectangle and, when it is moved into the space of the green rectangle, it shouldn't be shown,

I used the above code to show the effect that I'm talking about, but the problem is, in my code, the blue disk is just covered by the green rectangle. It's still being drawn by the graphics expression.

How do I actually confine the plot range of the blue disk to the red region without redefining the range of the control specified by {cross, 0, 1}?

Update: Inset[] works very well :) enter image description here

$\endgroup$
3
  • $\begingroup$ Do you want simply to confine the blue circle to the red region? This could be done by restricting the value of the translation to e.g.: {8 Min[.375, cross], 1} $\endgroup$ – Daniel Huber Sep 15 '20 at 10:46
  • $\begingroup$ No, i don't want to make any change to Translate[], as i mentioned, the overall effect is shown in my code, but the Disk[] actually hides behind the green rectangle when it leaves red region, is it possible to make it not display at all if it's outside the red region. $\endgroup$ – DORA Sep 15 '20 at 12:53
  • $\begingroup$ In graphics[], if i define the plotrange, then the object or part of the object will not be displayed if it crosses the plotrange boundary,but i don't know how to confine an object in a finite region in Graphics $\endgroup$ – DORA Sep 15 '20 at 13:00
1
$\begingroup$

Here's a solution using Inset:

clipRange = {{0, 5}, {0, 5}};
Manipulate[
 Graphics[
  {
   Red, Rectangle[{0, 0}, {5, 5}],
   Inset[
    Graphics[
     {Blue, Translate[Disk[{1, 1}, 1], {8 cross, 1}]},
     PlotRange -> clipRange
     ],
    First /@ clipRange,
    ImageScaled@{0, 0},
    -Subtract @@@ clipRange
    ],
   Opacity@0.5, Green, Rectangle[{5, 5}, {10, 0}]
   },
  PlotRange -> All
  ],
 {cross, 0, 1}
 ]

Essentially, we are creating a second Graphics with the stuff to be clipped (here the disk), and then we carefully position the Inset to occupy the correct region in the outer Graphics:

  • The plot range of the inner Graphics is set to clipRange
  • The position is set to the lower left corner of the clipRange
  • The reference position in the inner coordinate system is set to the lower left corner with ImageScaled@{0,0} (in theory, First/@clipRange would also work, but that solution doesn't quite work with PlotRange->All and ImagePadding->Automatic)
  • The size of the inset is set to the size of the clipRange

Compared to the other solutions, this has the advantage that the placement of the "clipping region" can be anywhere inside the plot range (as opposed to the GraphicsRow solution), and that there is no need to call the potentially expensive and fragile function RegionIntersection. The code can also easily be extracted into a wrapper function that can be put around arbitrary graphics primitives:

ClipObjects[prim_, clipRange_] :=
 Inset[
  Graphics[
   prim,
   PlotRange -> clipRange
   ],
  First /@ clipRange,
  ImageScaled@{0, 0},
  -Subtract @@@ clipRange
  ]

Manipulate[
 Graphics[
  {
   Red, Rectangle[{0, 0}, {5, 5}],
   ClipObjects[
    {Blue, Translate[Disk[{1, 1}, 1], {8 cross, 1}]},
    {{0, 5}, {0, 5}}
   ],
   Opacity@0.5, Green, Rectangle[{5, 5}, {10, 0}]
   },
  PlotRange -> All
  ],
 {cross, 0, 1}
 ]
(* same output *)

This does exactly the same as the code above, but the code is nicely separated from the graphics expression.

$\endgroup$
1
  • $\begingroup$ Thanks, Inset[] is easier to be added to my original code without too much modulation on Graphics[] $\endgroup$ – DORA Sep 16 '20 at 14:42
2
$\begingroup$

Update I don't know how to clipping a graphics by using a closed curves in MMA. Here we using RegionIntersection to obtain the DiskSegment etc.

Clear["`*"];
reg[cross_] := 
  RegionPlot[
   RegionIntersection[Disk[{0, 0}, 4], Disk[{1, 2.5} + {cross, 0}, 1],
     PerformanceGoal -> "Quality"], PlotPoints -> 200, 
   PlotStyle -> Blue];
Manipulate[
 Show[Graphics[{Red, Disk[{0, 0}, 4]}], reg[cross]], {cross, -5, 5}]

enter image description here

Original

Clear["`*"];
reg[cross_] = 
  RegionIntersection[Rectangle[{0, 0}, {5, 5}], 
   Disk[{1, 2.5} + {8 cross, 0}, 1]];
Manipulate[
 Graphics[{Red, Rectangle[{0, 0}, {5, 5}], Blue, reg[cross], Green, 
   Opacity[0.2], Rectangle[{5, 5}, {10, 0}]}, 
  PlotRange -> All], {cross, 0, 1}]

enter image description here

$\endgroup$
2
  • $\begingroup$ It went wrong when the blue disk reached the boundary between two rectangles. $\endgroup$ – DORA Sep 16 '20 at 9:57
  • 1
    $\begingroup$ @DORA I had fixed the problem by defined the region function outside the Manipulate $\endgroup$ – cvgmt Sep 16 '20 at 10:49
1
$\begingroup$

I am not sure I understand what you are requesting, but here is my interpretation.

Manipulate[
  GraphicsRow[
    {Graphics[
       {Red, Rectangle[{0, 0}, {5, 5}],
        Blue, Translate[Disk[{1, 2.5}, 1], {8 cross, 0}]},
       PlotRange -> {{0, 5}, {0, 5}}],
     Graphics[
      {FaceForm[{Green, Opacity[.6]}], Rectangle[{0, 0}, {5, 5}]},
      PlotRange -> {{0, 5}, {0, 5}}]},
    Spacings -> 0],
 {cross, 0, 1, .1, Appearance -> "Labeled"}]

manip

With this code you will see the blue disk get clipped as it passes through the right edge of the red rectangle. Since the green rectangle is not fully opaque, the blue disk would be visible in the green rectangle if it weren't being clipped.

$\endgroup$
2
  • $\begingroup$ Thanks, but it's better if there's only one Graphics[]. $\endgroup$ – DORA Sep 16 '20 at 9:54
  • 1
    $\begingroup$ @DORA. I fully agree, but this is not a simple problem, and this approach tries to solve your problem with as little change to your code as possible. $\endgroup$ – m_goldberg Sep 16 '20 at 14:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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