[postgis-users] How to generalize or simplify a Polygon

oscar.gomez at telvent.abengoa.com oscar.gomez at telvent.abengoa.com
Thu Aug 28 08:48:44 PDT 2003


This is an ArcView-Avenue implementation of the Douglas - Peucker 
algorithm to generalize a polyline or polygon feature's vertices.

Good luck,

Oscar Gomez
IT Consultant
Telvent


theView = av.GetActiveDoc
thePrj = theView.GetProjection
if (thePrj.IsNull) then
  hasPrj = false
else
  hasPrj = true
  thePrj = theView.GetProjection
end

' Get active themes

theThemes = theView.GetActiveThemes

if (theThemes.Count < 1) then
  MsgBox.Error("Please make a polyline or polygon theme active","*** Error 
***")
  exit
end

' Process each active theme

for each t in theThemes

  ' Check that the theme is of the correct type

  if (t.Is( FTHEME).Not) then
    MsgBox.Error (t.GetName++"is not a polyline or polygon theme","*** 
Error ***")
    continue
  end

  theClassName = t.GetFTab.GetShapeClass.GetClassName
  if ((theClassName = "Polygon").Not and (theClassName = "Polyline").Not) 
then
    MsgBox.Error (t.GetName++"is not a polyline or polygon theme","*** 
Error ***")
    continue
  end

  ' Get a tolerance in (distance units) to be used (must be > 0)

  theTol = 0
  theMUnits = theView.GetDisplay.GetUnits
  theDUnits = theView.GetDisplay.GetDistanceUnits
  theUStr = Units.GetFullUnitString(theDUnits).LCase
  while ((theTol <= 0) or (theTol.AsString.IsNumber).Not)
    theTol = MsgBox.Input("Positive tolerance value (in "+theUStr+
         ") for theme"++t.GetName,"Tolerance",theTol.AsString)
    if (theTol = NIL) then exit end

    if (theTol.IsNumber) then
      theTol = theTol.AsNumber
    end
  end
  theTol = Units.Convert(theTol,theDUnits,theMUnits)

  ' Get the name for a new theme, from View.Export script

  def = av.GetProject.MakeFileName("theme", "shp")
  def = FileDialog.Put(def, "*.shp", "New file for simplified "+ 
t.getName)

  if (def = NIL) then return nil end

  ' Create a new shapefile theme, from View.Export script

  tbl = t.GetFtab
  shpfld = (tbl.FindField("Shape"))
  if (shpfld.IsVisible.Not) then
    shpfld.SetVisible(shpfld.IsVisible.Not)
    WasNotVisible = TRUE
  else
    WasNotVisible =FALSE
  end

  ' This will only export the selected shapes, if any have been selected

  av.ShowMsg("Creating new shape file from"++ t.GetName)
  anFTab = tbl.Export(def, Shape, tbl.GetSelection.Count > 0)
  anFTab.SetEditable(true)

  if (WasNotVisible) then
    shpfld.SetVisible(FALSE)
  end

  ' Find the shape field

  theSField = anFTab.FindField("Shape")

  ' Set up status bar

  av.ShowMsg("Generalizing new shapes from theme"++ t.GetName)
  theSize = anFTab.GetNumRecords

  ' Initialize counters for reporting

  count = 0
  oldCount = 0
  newCount = 0

  ' Process each shape

  for each r in anFTab

    av.SetStatus(100*count/theSize)

    ' Retrieve shape

    if (theClassName = "Polygon") then
      theOShape = Polygon.MakeNull
    else
      theOShape = Polyline.MakeNull
    end
    anFTab.QueryShape(r,theView.GetProjection,theOShape)

    ' Make a list for collecting the new set of point lists

    theNShape = List.Make

    ' Process each list in the ListofListofPoints

    for each p in theOShape.AsList

      ' Make a list for collecting the vertices to keep

      theNList = List.Make

      oldCount = oldCount + p.Count

      ' Set up stack for holding a set of lists of form {index,point}

      theStack = Stack.Make

      ' Add first point to the list being assembled, and make it the 
anchor

      theAnchor = p.Get(0)
      if (hasPrj) then
        theNList.Add(theAnchor.ReturnUnProjected(thePrj))
      else
        theNList.Add(theAnchor)
      end
      aIndex = 0

      ' Add last point to stack

      fIndex = p.Count - 1
      theStack.Push({fIndex,p.Get(fIndex)})

      ' Process the points with the Douglas - Peucker approach

       while (theStack.IsEmpty.Not)

        ' Process from Anchor (beginning) to Floater (top of stack)

        fIndex = theStack.Top.Get(0)

        ' Create graphic shape for comparing distances

        theVect = Line.Make(theAnchor,theStack.Top.Get(1))

        ' Initialize values for comparison

        theMax = theTol
        mxIndex = 0

        ' Find distance

        for each i in (aIndex + 1) .. (fIndex - 1) ' process middle points

          dist = theVect.Distance(p.Get(i))

          ' Check against previous maximum

          if (dist >= theMax) then  ' this point is out of the tolerance
            theMax = dist
            mxIndex = i
          end

        end

        ' If a vertex is found outside the current tolerance corridor,
        ' push it onto the stack

        if (mxIndex > 0) then 'a new floater has been found
          theStack.Push({mxIndex,p.Get(mxIndex)})
        else  ' add floater to the list for the new shape and move forward
          if (hasPrj) then
            theNList.Add(theStack.Top.Get(1).ReturnUnProjected(thePrj))
          else
            theNList.Add(theStack.Top.Get(1))
          end

          ' Make the floater the new anchor

          theAnchor = theStack.Pop.Get(1)
          aIndex = fIndex

        end

      end

      ' Check for collapsed polygons

      if ((theNList.Count < 4) and (theClassName = "Polygon")) then
         ' Revert to original polygon
        if (hasPrj) then
          theNList = List.Make
          for each pt in p
            theNList.Add(pt.ReturnUnProjected(thePrj))
          end
        else
          theNList = p
        end

      end

      ' Finish up individual lists

      newCount = newCount + theNList.Count
      theNShape.Add(theNList)

    end

    ' Finish up the shape

    if (theClassName = "Polygon") then
      theNShape = Polygon.Make(theNShape)
    else
      theNShape = Polyline.Make(theNShape)
    end
    anFTab.SetValue(theSField, r, theNShape)
    count = count + 1

  end

  ' Clear status message

  av.ClearMsg
  av.ClearStatus

  ' Report on counts of old and new theme

  MsgBox.Info("The old theme with"++ oldCount.AsString ++
      "vertices has been generalized to"++
        newCount.AsString++"vertices","Results")

  ' Create a theme and add it to the View

  anFTab.SetEditable(false)
  fthm = FTheme.Make(anFTab)
  theView.AddTheme(fthm)

end

' Bring the View to the front

theView.GetWin.Activate




"Matt Lynch" <matt at terraEngine.com>


"Matt Lynch" <matt at terraEngine.com>
Enviado por: postgis-users-bounces at postgis.refractions.net
28/08/2003 17:45
Por favor, responda a PostGIS Users Discussion

 
        Para:   <postgis-users at postgis.refractions.net>
        cc: 
        Asunto: [postgis-users] How to generalize or simplify a Polygon


Hi,

I have an application where I will be accepting a shape file (polygon)
to define a region of permitted access for a user which will be imported
to postgis.  That shape file has the potential to have many points if
the region defined has a border like a river or lake.  Are there any
functions or tools available that would take a polygon shape and reduce
or generalize the number of points in the polygon?  The resulting
polygon must cover at least as much area as the original.

Thanks,

Matt

---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.507 / Virus Database: 304 - Release Date: 8/4/2003
 



_______________________________________________
postgis-users mailing list
postgis-users at postgis.refractions.net
http://postgis.refractions.net/mailman/listinfo/postgis-users






More information about the postgis-users mailing list