Little Chandler is sad. Draw him a cloud to cheer him up

T-SQL 235 234 229 212 171 73 bytes

This makes use of spatial functionality in SQL Server 2012+. When it is run in SSMS (SQL Server Management Studio) is produces a spatial results pane. The input is from variable @i. I could reduce it further if the input could be taken from a table.

Since table input is now allowed.

SELECT Geometry::UnionAggregate(Geometry::Point(X,Y,0).STBuffer(R))FROM A

I've left the previous solution below.

DECLARE @ VARCHAR(999)='WITH a AS(SELECT *FROM(VALUES('+REPLACE(@i,' ','),(')+'))A(X,Y,R))SELECT Geometry::UnionAggregate(Geometry::Point(X,Y,0).STBuffer(R))FROM a'EXEC(@)

Edit: Remove stray space, surplus into and subquery

171: Replaced table creation with CTE and @s with @.

enter image description here

Break down of the Dynamic SQL

DECLARE @i VARCHAR(100) = '1,4,2 5,2,1 3,1,1 3.5,2,1.2 3,3,0.7 1,2,0.7' -- Input
DECLARE @ VARCHAR(999) = '
WITH a AS(                                       --CTE to produce rows of x,y,r 
    SELECT *FROM(VALUES('+
        REPLACE(@i,' ','),(')                    --Format @i to a value set
        +'))A(X,Y,R)
)
SELECT Geometry::UnionAggregate(                 --Aggregate Buffered Points
    Geometry::Point(X,Y,0).STBuffer(R)           --Create point and buffer
    )               
FROM a                                           --from the table variable
'
EXEC(@)                                          --Execute Dynamic sql

Mathematica 177 126 121 119

Solving by Disk Regions: the mathematician's approach

The logic is to

  • Create Region 1 (R1), the circles (without their interiors);
  • Create Region 2 (R2), the disks (without the circle borders).
  • Create Region 3 (R3 = R1-R2).
  • -

region inference

This is precisely the approach taken below. It produced the 3 figures above.

input = "3,1,1 3,2,1.5 1,2,0.7 0.9,1.2,1.2 1,0,0.8";
circles = ((x - #)^2 + (y - #2)^2 == #3^2) & @@@ 
     ToExpression[#~StringSplit~","] &@(StringSplit@input);
R1 = ImplicitRegion[Or @@ circles, {x, y}];
r1 = RegionPlot[R1, PlotLabel -> "R1: circles containing borders", 
   AspectRatio -> 1, PlotRange -> {{-1, 5}, {-1, 5}}];

innerDisks = ((x - #)^2 + (y - #2)^2 < #3^2) & @@@ 
     ToExpression[#~StringSplit~","] &@(StringSplit@input);
R2 = ImplicitRegion[Or @@ innerDisks, {x, y}];
r2 = RegionPlot[R2, PlotLabel -> "R2: disks within circle borders", 
   AspectRatio -> 1, PlotRange -> {{-1, 5}, {-1, 5}}];
R3 = RegionDifference[R1, R2]
r3 = RegionPlot[R3, PlotLabel -> "R3 = R1-R2", AspectRatio -> 1, 
   PlotRange -> {{-1, 5}, {-1, 5}}];
GraphicsGrid[{{r1, r2, r3}}, ImageSize -> 600]

Implicit region #1 is the union of the circles. Implicit region #2 is the union of the disks lying within the circles. Their difference is the border.

RegionDifference[
ImplicitRegion[(-3 + x)^2 + (-1 + y)^2 == 1 || (-3 + x)^2 + (-2 + y)^2 == 2.25 || (-1 + x)^2 + (-2 + y)^2 == 0.49 || (-0.9 + x)^2 + (-1.2 + y)^2 == 1.44 || (-1 + x)^2 + y^2 == 0.64, {x, y}],
ImplicitRegion[(-3 + x)^2 + (-1 + y)^2 < 1 || (-3 + x)^2 + (-2 + y)^2 < 2.25 || (-1 + x)^2 + (-2 + y)^2 < 0.49 || (-0.9 + x)^2 + (-1.2 + y)^2 < 1.44 || (-1 + x)^2 + y^2 < 0.64, {x, y}]]


Solving by Disk Regions: the engineer's approach (119 chars)

The following takes the union of the disk regions, discretizes that region, and finds it's boundary. The points in the diagram demarcate the intervals of the Delaunay mesh. We display the discretized region below to highlight the object that furnishes the boundary of interest (the outline of the cloud).

s = StringSplit;RegionBoundary@DiscretizeRegion[RegionUnion[Disk[{#, #2}, #3] &@@@
ToExpression[#~s~","] &@(s@InputString[])]]

"3,1,1 3,2,1.5 1,2,0.7 0.9,1.2,1.2 1,0,0.8"

The region boundary is discretized.

reg1


Solving by Detecting Edges: The Photographer's Approach - 121 chars

edge detection

It draws the disks in black, rasterizes the image, detects the edges, and inverts black and white.

s=StringSplit;ColorNegate@EdgeDetect@Rasterize@Graphics[Disk[{#,#2},#3]&@@@
((ToExpression/@s[#,","])&/@s[InputString[]])]

Mathematica, 175 158 149 bytes

s=StringSplit;l=ToExpression[#~s~","]&@s@InputString[];RegionPlot[Or@@(Norm@{x-#,y-#2}<#3&@@@l),{x,m=Min@(k={{##}-#3,{##}+#3}&@@@l),M=Max@k},{y,m,M}]

I remember from discussion in the sandbox that this approach was supposed to be valid, but I'm not entirely sure how it sits with the new wording of the rules, so @Lilac, let me know if you think this violates the rules.

Basically, I'm creating a logical condition which is true for all points inside the cloud and false for all points outside it. I'm feeding that to RegionPlot which then renders the region of all points where the expression is True as well as an outline around it.

enter image description here

Ungolfed:

s = StringSplit;
l = ToExpression[#~s~","] &@s@InputString[];
RegionPlot[
 Or @@ (Norm@{x - #, y - #2} < #3 & @@@ l), 
 {x, m = Min@(k = {{##} - #3, {##} + #3} & @@@ l), M = Max@k},
 {y, m, M}
]