// The following SDL was written by Chris Bartlett as part of the POV-Person library // It can be reused in original or modified format with or without the permission of the author // The ppCrowd macro positions a series of figures at a set of positions that have been predefined // and stored in an array. // // Parameters: // ----------- // ppFirstPosition - First position to use // ppNumberOfFigures - The number of figures to position #macro ppCrowd(ppFirstPosition, ppNumberOfFigures) #ifndef(ppCrowdFigureMinRotation) #declare ppCrowdFigureMinRotation = 0; #end // Minimum amount to rotate a figure by #ifndef(ppCrowdFigureMaxRotation) #declare ppCrowdFigureMaxRotation = 360; #end // Maximum amount to rotate a figure by #ifndef(ppCrowdRand) #declare ppCrowdRand = seed(21); #end #local ppI = 0; #local ppFigureListDim = dimension_size(ppCrowdFigureList,1); union { #while (ppI
  • not too close to other points,
  • that the surface // is not too steep and
  • that the point is not too close to an edge. // // Parameters: // ----------- // ppNewFigures - The number of figures required #macro ppCrowdPositions(ppNewFigures) #include "shapes.inc" // #local ppCrowdRand = seed(ppCrowdSeed); #ifndef(ppCrowdRand) #declare ppCrowdRand = seed(38); #end #ifndef(ppCrowdPositionMaxTries) #declare ppCrowdPositionMaxTries = 100; #end // Control number to avoid infinite loops if the surface is too small for the number of positions requested. #ifndef(ppFigurePositions) #declare ppFigurePositions = array[ppNewFigures]; #end #ifndef(ppFigureCounter) #declare ppFigureCounter = 0; #end #ifndef(ppCrowdFigureSeparation ) #declare ppCrowdFigureSeparation = 0.5; #end // Minimum separation between the centres of any two positions #ifndef(ppCrowdDistanceFromEdge ) #declare ppCrowdDistanceFromEdge = 0.25; #end // Minimum distance of a position from an edge on the objects surface #ifndef(ppCrowdPermittedDrop ) #declare ppCrowdPermittedDrop = 0.1; #end // Maximum change of height before it's considered an edge #ifndef(ppCrowdEdgeDetectionSamples) #declare ppCrowdEdgeDetectionSamples = 4; #end // Number of samples taken around a position when looking for edges #ifndef(ppCrowdPlatform) #declare ppCrowdPlatform = box{<0,-0.001,0>,<10,0,10>} #end // Default surface is a 10 unit square starting at the origin #local ppPlatformMin = <0,0,0>; #local ppPlatformMax = <0,0,0>; #local ppPlatformNormal = <0,0,0>; Extents(ppCrowdPlatform, ppPlatformMin, ppPlatformMax) #local ppCrowdExtents = ppPlatformMax - ppPlatformMin; #local ppStartTraceHeight = 2*ppPlatformMax.y; #local ppI=0; #local ppTryCount=0; #local ppTotalTryCount=0; #local ppTraceVector = <0,-1,0>; #local ppRimIntersectionNormal = <0,0,0>; #while (ppI; #while ((vlength(ppIntersectionNormal)=0 | ppSurfaceNotGood=1) & ppTryCount*ppCrowdExtents+ppPlatformMin*<1,0,1>+ppStartTraceHeight*y; #declare ppIntersectionPoint = trace ( ppCrowdPlatform, ppTraceStart, ppTraceVector, ppIntersectionNormal ); #local ppSurfaceNotGood = 0; #if (vlength(ppIntersectionNormal)!=0) #local ppJ = 1; // Sample around the area to avoid getting too close to surface edges #while (ppJ <= ppCrowdEdgeDetectionSamples) #local ppTraceRimStart = ppTraceStart + vrotate(x,y*ppJ*360/ppCrowdEdgeDetectionSamples)*ppCrowdDistanceFromEdge; #local ppRimPoint = trace ( ppCrowdPlatform, ppTraceRimStart, ppTraceVector, ppRimIntersectionNormal ); #if (vlength(ppIntersectionNormal)=0 | abs(ppIntersectionPoint.y-ppRimPoint.y) > ppCrowdPermittedDrop) #local ppSurfaceNotGood = 1; #end #local ppJ = ppJ + 1; #end #end #local ppTryCount = ppTryCount + 1; #local ppTotalTryCount = ppTotalTryCount + 1; #end #if (ppTryCount,5 scale <1,0.25,1>} #declare ppCrowdFigureList = array[3] { sphere {<0,0.2,0>,0.2 pigment {color rgb <1,1,0>}} sphere {<0,0.1,0>,0.1 pigment {color rgb <1,0,1>}} sphere {<0,0.2,0>,0.2 pigment {color rgb <0,1,0>}} }; #local ppPositionCount = ppCrowdPositions(500); ppCrowd(0,ppPositionCount) object {ppCrowdPlatform pigment {rgb <0,1,1>}} camera {location <0,4,-10> look_at <0,0,0>} light_source {<0,18,-3> color rgb 1}