Thursday, February 28, 2013

proj4 used to define custome projection in quantum GIS

Learnt this while trying to get NLCD (National Land Cover Dataset) reprojected to NAD.
In order to define a custom projection in quantum GIS, one has to use the proj4 format:
The final proj4 string: +proj=aea +lat_1=29.5 +lat_2=45.5 +lat_0=23 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs
The spatial reference information in metadata:
Spatial_Reference_Information:
  Horizontal_Coordinate_System_Definition:
    Planar:
      Map_Projection:
        Map_Projection_Name: Albers Conical Equal Area
        Albers_Conical_Equal_Area:
          Standard_Parallel: 29.500000
          Standard_Parallel: 45.500000
          Longitude_of_Central_Meridian: -96.000000
          Latitude_of_Projection_Origin: 23.000000
          False_Easting: 0.000000
          False_Northing: 0.000000
      Planar_Coordinate_Information:
        Planar_Coordinate_Encoding_Method: row and column
        Coordinate_Representation:
          Abscissa_Resolution: 30.000000
          Ordinate_Resolution: 30.000000
        Planar_Distance_Units: meters
    Geodetic_Model:
      Horizontal_Datum_Name: North American Datum of 1983
      Ellipsoid_Name: Geodetic Reference System 80
      Semi-major_Axis: 6378137.000000
      Denominator_of_Flattening_Ratio: 298.257222


Wednesday, February 27, 2013

Friendly SQLite output

Original is here: http://www.johnhawthorn.com/2010/11/friendlier-sqlite-output/

SQLite is extremely handy for embedded, desktop and development uses. However with default settings it can seem somewhat less friendly to use directly than the server based databases like MySQL and PostgreSQL.

With defaults:

1
2
3
4
5
6
7
8
9
10
$ sqlite3 db/dev.sqlite3 
SQLite version 3.7.3
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from users;
1|Administrator|admin|2010-10-24 23:09:52|2010-10-25 07:24:34
2|John|jhawthorn|2010-10-24 23:09:52|2010-10-24 23:09:52
sqlite> 

Under these settings I found sqlite too awkward to use regularly. not particularly friendly when compared to mysql's default output

1
2
3
4
5
6
7
8
9
10
11
mysql> select * from users;
+----+---------------+-----------+---------------------+---------------------+
| id | first_name    | username  | created_at          | updated_at          |
+----+---------------+-----------+---------------------+---------------------+
|  1 | Administrator | admin     | 2010-10-24 23:09:52 | 2010-10-25 07:24:34 |
|  2 | John          | jhawthorn | 2010-10-24 23:09:52 | 2010-10-24 23:09:52 |
+----+---------------+-----------+---------------------+---------------------+
2 rows in set (0.00 sec)
mysql>

Adding a couple lines to ~/.sqliterc, which is run as sqlite opens, makes sqlite's output more like MySql's.

1
2
3
4
5
6
-- ~/.sqliterc
.header on    -- show column names
.mode column  -- show results in column format
.timer on     -- show execution time after each query

the result being

1
2
3
4
5
6
7
8
9
sqlite> select * from users;
id          first_name     login       created_at           updated_at                
----------  -------------  ----------  -------------------  -------------------
1           Administrator  admin       2010-10-24 23:09:52  2010-10-25 07:24:34
2           John           jhawthorn   2010-10-24 23:09:52  2010-10-24 23:09:52       
CPU Time: user 0.000000 sys 0.000000
sqlite>

With this tweak, I now prefer using sqlite for development, Giving me familiarity as long time MySQL user and having sqlite's advantages and simplicity.

 

Monday, February 25, 2013

Update sqlite database in C#

string dataSource = "Database.s3db";
using (SQLiteConnection connection = new SQLiteConnection())
{
    connection.ConnectionString = "Data Source=" + dataSource;
    connection.Open();
    using (SQLiteCommand command = new SQLiteCommand(connection))
    {
        command.CommandText =
            "update Example set Info = :info, Text = :text where ID=:id";
        command.Parameters.Add("info", SQLiteType.Text).Value = textBox2.Text; 
        command.Parameters.Add("text", SQLiteType.Text).Value = textBox3.Text; 
        command.Parameters.Add("id", SQLiteType.Text).Value = textBox1.Text; 
        command.ExecuteNonQuery();
    }
}

Friday, February 22, 2013

Balaji Viswanathan on Quora: How do the startups that offer free web services make money

Most free web services plan to make money by the following:
  1. Advertising model - Know as much as possible about the user and bring targeted ads. 
  2. Freemium model - sell a free product and plan to convert some of them to a paid plan.
  3. Limited period promotion - Start with the free product for a promotional initial period and plan to charge it later. For instance, 37 Signals provides free 30 day trial offer for most products and then charge if you use later. This is a tough thing to master these days.
  4. Sponsorship model - If your service indirectly helps the government and/or major organizations you could ask them to sponsor your service.
  5. Wikipedia model -  You could get donations from your users. Many wordpress plugins, open source tools and Wikipedia do this. This could be the future of newspapers.
  6. Gillette model - Printers and razors are sold less than cost, as they plan to make high margin from selling a complementary product (cartridge/blades). The printer or blade you purchased will turn worthless if you don't buy the super-high margin complementary products from the manufacturer. On the web, for instance, you could create a cloud based spreadhseet/wordprocessr that is free to edit/create documents, but charged money for exporting it as a file to the local machine. Or you could charge high for the iPhone app that can access the data natively.
  7. Open Source Model - Sell the product for free and plan to make money on support, customization and installation. Most open source software follow this model.
  8. Usage charge model - This is related to the freemium model. Give the product free for low usage, but charge when the user is exceeding the free limits (many storage applications such as Dropbox fall under this). 
  9. Zynga model - Sell products through in-app purchases or to get forward in the game.
  10. Credit card model - In this model, you make your product free for one side (consumers) and use the network effects to make the other side (merchants) pay. Facebook, Yelp and other online marketplaces are now getting on to the model.
  11. Upsell/Cross-sell - Sell a free product & use that to promote a premium product in the same segment. For instance, If you run a finance website, you could give stock quotes free and sell premium analyst reports and financial planning tools.
  12. Build a brand - Use the free service to get brownie points/good press and use the brand image to sell premium products (directly related or not) later.
  13. Affiliate marketing - Signup for affiliate programs related to your service and convert your users to customers of your affiliates.
  14. Sell it to Google - Build a big user base that might attract a big buyer such as Microsoft or Google, who might use the user base to sell their premium products/services.
  15. Make your next venture a success - If none of the previous stuff works, you could run a free venture to build your personal brand/get popular and hope to get funding for your next venture.

Wednesday, February 20, 2013

Relationship between length of CFTID and the number of points in geometry

select 
  len(_CFTID), avg(GEOMETRY_BIN.STNumPoints())
  from
  [PARCEL_DATA].[dbo].[ParcelDetail]
  where
  _CFTID like '03200012%'
  group by
  LEN(_cftid)
  order by
  LEN(_cftid)



Len     NumPoints
10       199826
11       969
12       16
13       33
14       380
15       30
16       18
17       17
18       10
19       8
20       6
21       10

Tuesday, February 19, 2013

GetCenterPtFromLn

private SqlGeometry GetCenterPtFromLn(SqlGeometry rd)
        {
            int n = rd.STNumPoints().Value;
            Vector centpt;
            if (n % 2 == 0)
            {
                Vector pt1 = new Vector(rd.STPointN(n / 2).STX.Value, rd.STPointN(n / 2).STY.Value),
                    pt2 = new Vector(rd.STPointN(n / 2 + 1).STX.Value, rd.STPointN(n / 2 + 1).STY.Value);
                centpt = (pt1 + pt2) / 2;
            }
            else
                centpt = new Vector(rd.STPointN((n + 1) / 2).STX.Value, rd.STPointN((n + 1) / 2).STY.Value);
            return Point2PointGeometry(centpt);
        }

GetBufferWithoutCap


public SqlGeometry GetBufferWithoutCap(SqlGeometry rd, double bufsize, double indentLen)
        {
            int n = rd.STNumPoints().Value;
            Vector startpt = new Vector(rd.STPointN(1).STX.Value, rd.STPointN(1).STY.Value),
                startpt2 = new Vector(rd.STPointN(2).STX.Value, rd.STPointN(2).STY.Value),
                endpt = new Vector(rd.STPointN(n).STX.Value, rd.STPointN(n).STY.Value),
                endpt2 = new Vector(rd.STPointN(n - 1).STX.Value, rd.STPointN(n - 1).STY.Value),
                startln = startpt - startpt2, endln = endpt - endpt2,
                startNormln = new Vector(startln.Y * -1, startln.X), endNormln = new Vector(endln.Y * -1, endln.X);
            if (startpt == endpt)
                return rd.Reduce(0.00001).STBuffer(bufsize);
            startNormln.Normalize(); startln.Normalize();
            endNormln.Normalize(); endln.Normalize();
            SqlGeometry startCap = Point2LineGeometry(new Vector[2] { startpt - startln * indentLen + startNormln * bufsize, startpt - startln * indentLen - startNormln * bufsize }),
                endCap = Point2LineGeometry(new Vector[2] { endpt - endln * indentLen + endNormln * bufsize, endpt - endln * indentLen - endNormln * bufsize }),
                buffer = rd.Reduce(0.00001).STBuffer(bufsize).STDifference(startCap.STBuffer(0.00001)).STDifference(endCap.STBuffer(0.00001));
            SqlGeometry realbuf = new SqlGeometry();
            int k = 0;
            SqlGeometry centpt = GetCenterPtFromLn(rd).STBuffer(0.00001);
            for (int i = 0; i < buffer.STNumGeometries(); i++)
            {
                SqlGeometry sg = buffer.STGeometryN(i + 1);
                if (sg.Filter(centpt))
                {
                    if (k++ == 0)
                        realbuf = sg;
                    else
                        realbuf = realbuf.STUnion(sg);
                }
            }
            return realbuf;
        }

fail implementation of GetIsometriLine, too many bugs

#region fail implementation of GetIsometriLine, too many bugs
        public SqlGeometry GetIsometricLine(SqlGeometry rd, ref Vector startpt, ref Vector endpt, ref bool shortRd, SqlGeometry imp, bool IntersectAtStart, double validLen, double lnLen)
        {
            SqlGeometry jnct =new SqlGeometry();
            Vector jnctpt, rdend, impend;
            if (IntersectAtStart)
                jnct = rd.STStartPoint();
            else
                jnct = rd.STEndPoint();
            jnctpt = new Vector(jnct.STX.Value, jnct.STY.Value);
            if (shortRd)
                rdend = startpt;
            else
            {
                if (IntersectAtStart)
                {                                        
                    if (startpt != new Vector(-9999, -9999))
                        rdend = startpt;
                    else
                    {                        
                        if (rd.STLength() < validLen)
                        {
                            SqlGeometry centpt = GeoUtils.Reduce2NumPoints(rd,1000).STBuffer(0.00002).STCentroid();
                            rdend = new Vector(centpt.STX.Value, centpt.STY.Value);
                            startpt = rdend;
                            endpt = rdend;
                            shortRd = true;
                        }
                        else
                        {
                            int np = rd.STNumPoints().Value;
                            if (np == 2)
                            {
                                rdend = new Vector(rd.STEndPoint().STX.Value, rd.STEndPoint().STY.Value);
                                startpt = rdend;                                
                            }
                            else
                            {
                                double len = jnct.STDistance(rd.STPointN(2)).Value;
                                Vector pt = new Vector(rd.STPointN(2).STX.Value, rd.STPointN(2).STY.Value);
                                int p=2;
                                while (len < validLen)
                                {
                                    p++;
                                    Vector ppt = new Vector(rd.STPointN(p).STX.Value, rd.STPointN(p).STY.Value);
                                    len += rd.STPointN(p-1).STDistance(rd.STPointN(p)).Value;
                                    pt = (pt + ppt) / 2;
                                }
                                rdend = pt;
                                startpt=rdend;
                            }                            
                        }
                    }                    
                }
                else
                {
                    if (endpt != new Vector(-9999, -9999))
                        rdend = endpt;
                    else
                    {                        
                        if (rd.STLength() < validLen)
                        {
                            SqlGeometry centpt = GeoUtils.Reduce2NumPoints(rd,1000).STBuffer(0.00002).STCentroid();
                            rdend = new Vector(centpt.STX.Value, centpt.STY.Value);
                            startpt = rdend;
                            endpt = rdend;
                            shortRd = true;
                        }
                        else
                        {
                            int np = rd.STNumPoints().Value;
                            if (np == 2)
                            {
                                rdend = new Vector(rd.STStartPoint().STX.Value, rd.STStartPoint().STY.Value);                                
                                endpt = rdend;
                            }
                            else
                            {
                                double len = jnct.STDistance(rd.STPointN(np-1)).Value;
                                Vector pt = new Vector(rd.STPointN(np-1).STX.Value, rd.STPointN(np-1).STY.Value);
                                int p=np-1;
                                while (len < validLen)
                                {
                                    p--;
                                    Vector ppt = new Vector(rd.STPointN(p).STX.Value, rd.STPointN(p).STY.Value);
                                    len += rd.STPointN(p+1).STDistance(rd.STPointN(p)).Value;
                                    pt = (pt + ppt) / 2;
                                }
                                rdend = pt;
                                endpt=rdend;
                            }                            
                        }
                    }
                }
            }            
            //now the other arm
            if (imp.STLength() < validLen)
            {
                SqlGeometry centpt = GeoUtils.Reduce2NumPoints(imp,1000).STBuffer(0.00002).STCentroid();
                impend = new Vector(centpt.STX.Value, centpt.STY.Value);
            }
            else
            {
                SqlGeometry interpt = imp.STStartPoint();
                Vector pt = new Vector(interpt.STX.Value, interpt.STY.Value);
                int np = imp.STNumPoints().Value, p = 1, increment = 1;
                if ((pt - jnctpt).Length > 0.00002)
                {
                    interpt = imp.STEndPoint();
                    pt = new Vector(interpt.STX.Value, interpt.STX.Value);
                    p = np;
                    increment = -1;
                }
                if (np == 2)
                {
                    if (increment == 1)
                        impend = new Vector(imp.STEndPoint().STX.Value, imp.STEndPoint().STY.Value);
                    else
                        impend = new Vector(imp.STStartPoint().STX.Value, imp.STStartPoint().STY.Value);
                }
                else
                {
                    double len = interpt.STDistance(imp.STPointN(p + increment)).Value;
                    pt = new Vector(imp.STPointN(p + increment).STX.Value, imp.STPointN(p + increment).STY.Value);
                    while (len < validLen)
                    {
                        p = p + increment;
                        Vector ppt = new Vector(imp.STPointN(p).STX.Value, imp.STPointN(p).STY.Value);
                        len += imp.STPointN(p).STDistance(imp.STPointN(p + increment)).Value;
                        pt = (pt + ppt) / 2;
                    }
                    impend = pt;
                }
            }
            Vector rdvec = (rdend - jnctpt), impvec = (impend - jnctpt);
            if (Math.Abs(Vector.AngleBetween(rdvec, impvec)) < 10)
                return SqlGeometry.Null;
            rdvec.Normalize(); impvec.Normalize();
            Vector isopt = jnctpt + (rdvec + impvec) / 2, isovec = isopt - jnctpt;
            if (isovec.Length < 0.00002)
            {
                isovec = new Vector(rdvec.Y * -1, rdvec.X);
            }
            isovec.Normalize();
            try
            {
                return Point2LineGeometry(new Vector[2] { jnctpt - isovec * lnLen, jnctpt + isovec * lnLen });
            }
            catch
            {
                return SqlGeometry.Null;
            }
        }
        #endregion GetIsometricLine

UnionAndSplit

public void UnionAndSplit(ref SqlGeometry rd, ref List imps, bool IntersectAtStart)
        {                       
            SqlGeometry fullrd = rd;
            Dictionary jnctdict =new Dictionary();
            if(IntersectAtStart)
                jnctdict.Add(rd.STStartPoint(), 1);
            else
                jnctdict.Add(rd.STEndPoint(), 1);
            foreach (SqlGeometry imp in imps)
            {
                if (imp.STIntersects(fullrd))
                {
                    SqlGeometry interpts = imp.STIntersection(fullrd);
                    for (int i = 0; i < interpts.STNumPoints(); i++)
                    {
                        SqlGeometry pti = interpts.STPointN(i + 1);
                        bool exist=false;
                        foreach (SqlGeometry pt in jnctdict.Keys.ToArray()) //not a good solution, but cannot think out a better one at this point
                        {
                            if (pti.STDistance(pt) < 0.00001)
                            {
                                jnctdict[pt]++;
                                exist = true;
                            }                            
                        }
                        if (!exist)
                            jnctdict.Add(pti, 1);
                    }
                }
                fullrd=fullrd.STUnion(imp);
            }
            if (jnctdict.Count == 1)
                return;
            imps=new List();
            foreach (SqlGeometry pt in (from v in jnctdict where v.Value > 2 select v.Key))
            {
                fullrd = fullrd.STDifference(pt.STBuffer(0.00001));
            }
            for (int i = 0; i < fullrd.STNumGeometries(); i++)
            {
                SqlGeometry rdi = fullrd.STGeometryN(i + 1);
                if (rdi.STTouches(rd))
                    rd = rdi;
                else
                    imps.Add(rdi);
            }
        }

Friday, February 15, 2013

Compare two Sql Buffering method: speed

declare @now as DateTime;
declare @a as geometry, @b as geometry, @c as geometry, @d as geometry;
declare @i as int;
set @a=geometry::STGeomFromText('POLYGON ((-117.728401504457 33.4074362777174, -117.728401504457 33.483708716929, -117.728741005063 33.483719997108, -117.729011997581 33.4837289974093, -117.729280993342 33.4837450012565, -117.729503005743 33.4837549999356, -117.729840993881 33.4838410019875, -117.730170994997 33.484004996717, -117.730409994721 33.4840710014105, -117.730654001236 33.4840999990702, -117.731106996536 33.4842299968004, -117.731616005301 33.4843790009618, -117.731675997376 33.4844399988651, -117.731721997261 33.4845660030842, -117.731923997402 33.4846879988909, -117.732126995921 33.4847859963775, -117.732163995504 33.4847979992628, -117.732271000743 33.4848320037127, -117.732706993818 33.4849689975381, -117.73326100409 33.4850199967623, -117.733397006989 33.4850059971213, -117.733499005437 33.4849639981985, -117.733560994267 33.4848840013146, -117.73358400166 33.4847370013595, -117.733613997698 33.4846950024366, -117.733650997281 33.4846429973841, -117.733763992786 33.4846339970827, -117.733796998858 33.4846389964223, -117.733940005302 33.4846619963646, -117.734024003148 33.4846379980445, -117.734120994806 33.4845350012183, -117.734171003103 33.4844639971852, -117.734221994877 33.4844399988651, -117.734347000718 33.4844729974866, -117.734402999282 33.4845250025392, -117.734414994717 33.4845909997821, -117.734381005168 33.4847190007567, -117.734347000718 33.48499699682, -117.734357997775 33.4851950034499, -117.734385997057 33.4853689968586, -117.734437003732 33.485449001193, -117.734442993999 33.485514998436, -117.734385997057 33.4855670034885, -117.734126001596 33.4856989979744, -117.733985006809 33.4858079999685, -117.733866006136 33.4859440028667, -117.733776003122 33.4861709997058, -117.733747005463 33.4863879978657, -117.733686000109 33.4865010008216, -117.73357899487 33.4866660013795, -117.733549997211 33.4867409989238, -117.733573004603 33.4868540018797, -117.733634993434 33.4870000034571, -117.733895003796 33.4874010011554, -117.73436999321 33.487999998033, -117.734623998404 33.4882310032845, -117.734861001372 33.4883939996362, -117.735148996115 33.4885940030217, -117.735771998763 33.4889089986682, -117.735934004188 33.4889699965715, -117.736111998558 33.4889959990978, -117.736368000507 33.4889869987965, -117.736644998193 33.4888830035925, -117.736771002412 33.4887949973345, -117.736844003201 33.4886910021305, -117.736984997988 33.4883240014315, -117.737027004361 33.4881620034575, -117.737038001418 33.4881189987063, -117.73707999289 33.4880620017648, -117.737111002207 33.4880620017648, -117.737131997943 33.4881670027971, -117.737231001258 33.4882630035281, -117.73738899827 33.488332003355, -117.737491995096 33.4884150028229, -117.737525001168 33.4884409978986, -117.737681999803 33.488480001688, -117.737749993801 33.4885059967637, -117.73787599802 33.4886680021882, -117.737885996699 33.4887159988284, -117.73787599802 33.4887640029192, -117.737775996327 33.4887899979949, -117.737775996327 33.4888430014253, -117.737834006548 33.4888859987259, -117.737807005644 33.4889120012522, -117.737734004855 33.488943003118, -117.737724006176 33.4889869987965, -117.73769800365 33.489009000361, -117.737608999014 33.4889909997582, -117.737588003278 33.4890170022845, -117.737618997693 33.4891130030155, -117.737602993846 33.4891659989953, -117.737498998642 33.4891259968281, -117.73745200038 33.4891439974308, -117.737398996949 33.4891960024834, -117.737188994884 33.4892230033875, -117.737158000469 33.4892269968987, -117.737007007003 33.4892570003867, -117.736965000629 33.4893010035157, -117.736948996782 33.4893800020218, -117.736974999309 33.4895370006561, -117.737038001418 33.4896859973669, -117.73707999289 33.4897420033813, -117.737131997943 33.489767998457, -117.737268000841 33.4898030012846, -117.73739400506 33.4898289963603, -117.737534999847 33.4898289963603, -117.737807005644 33.4896769970655, -117.737975001335 33.4895460009575, -117.73807400465 33.4895059987903, -117.738195002079 33.4895109981298, -117.738284006715 33.4895460009575, -117.738290995359 33.4895669966936, -117.738300994039 33.4895979985595, -117.738319993019 33.4896589964628, -117.73830999434 33.4896970018744, -117.738299995661 33.4897380024195, -117.738299995661 33.4898080006242, -117.738319993019 33.4898689985275, -117.738319993019 33.4899389967322, -117.738231003284 33.4901129975915, -117.738199993968 33.4901610016823, -117.738205000758 33.4902139976621, -117.738089993596 33.4904929995537, -117.738079994917 33.4905320033431, -117.738126993179 33.4905890002847, -117.738478004932 33.4906459972262, -117.7385610044 33.4906369969249, -117.738680005074 33.4905909970403, -117.738794997334 33.4905870035291, -117.738875001669 33.490615002811, -117.738885998726 33.4906679987907, -117.738881006837 33.4907160028815, -117.738839000463 33.4908339977264, -117.738916993141 33.4909470006824, -117.738888993859 33.4909709990025, -117.738805994391 33.4909709990025, -117.738764002919 33.4910190030932, -117.738768994808 33.4910449981689, -117.738800004125 33.4911110028625, -117.738727003336 33.4911630004644, -117.738710999489 33.4911940023303, -117.738717004657 33.4912509992719, -117.738721996546 33.4912990033627, -117.738753005862 33.4913289994001, -117.738794997334 33.4913209974766, -117.738820999861 33.4912810027599, -117.738820999861 33.4912159964442, -117.738857999444 33.4911850020289, -117.738894999027 33.4911980032921, -117.738921001554 33.4912239983678, -117.738951995969 33.4913770034909, -117.738967999816 33.4915610030293, -117.738931000233 33.4916350021958, -117.738848000765 33.4916869997978, -117.738800004125 33.4917220026255, -117.738658994436 33.4917659983039, -117.738527998328 33.4919139966369, -117.738370999694 33.4918790012598, -117.73832899332 33.4919229969382, -117.738303005695 33.4919620007277, -117.738313004375 33.4920630007982, -117.738334000111 33.4921239987016, -117.738365992904 33.4921720027924, -117.738475993276 33.4922460019588, -117.738585993648 33.4923069998622, -117.738658994436 33.4923200011253, -117.738784998655 33.4922159984708, -117.738852992654 33.4921979978681, -117.73894700408 33.4922069981694, -117.739114999771 33.4923420026898, -117.739240005612 33.4924689978361, -117.739256992936 33.4925170019269, -117.739278003573 33.4925910010934, -117.739262998104 33.4926349967718, -117.739215999842 33.4926439970732, -117.739146992564 33.4927349984646, -117.73904299736 33.492918998003, -117.73904299736 33.4929749965668, -117.739085003734 33.493014998734, -117.739231005311 33.4930189996958, -117.739372998476 33.4930759966373, -117.739393994212 33.4931240007281, -117.739366993308 33.4931539967656, -117.739305004478 33.4931679964066, -117.739209994674 33.4932679980993, -117.739115998149 33.4934910014272, -117.739078998566 33.4936610013247, -117.739063993096 33.4939099997282, -117.739068999887 33.4940150007606, -117.739087998867 33.4941150024533, -117.739187002182 33.4943249970675, -117.739397004247 33.4946649968624, -117.739867006755 33.495417136699, -117.824559478079 33.495417136699, -117.824307993054 33.4952220022678, -117.823504000902 33.4945980012417, -117.816596999764 33.4909979999065, -117.816356003284 33.4908730015159, -117.814840003848 33.4872070029378, -117.811278000474 33.4820199981332, -117.804418995976 33.4766160026193, -117.800633996725 33.4742129966617, -117.798559993505 33.472896002233, -117.798070997 33.4726089984179, -117.79326300323 33.4697820022702, -117.792353004217 33.4653469994664, -117.790478006005 33.4612419977784, -117.786994993687 33.4570280015469, -117.786757007241 33.4567539989948, -117.781470000744 33.4506559967995, -117.776062995195 33.4452909976244, -117.772342994809 33.4402370005846, -117.770768001676 33.4383350014687, -117.765139997005 33.4315399974585, -117.757411003113 33.4242829978466, -117.750887006521 33.4189750030637, -117.741410002112 33.4101179987192, -117.735336005688 33.4074369966984, -117.728401504457 33.4074362777174))',4269);
set @now=GETDATE();
set @i=0;
while @i<10
begin
 set @b=@a.STBuffer(0.0005);
 set @i=@i+1;
end

select CAST(DATEDIFF(MS, @now,GETDATE()) as CHAR(10));
set @now=GETDATE();
set @i=0;
while @i<10
begin
 set @c=@a.STEnvelope();
 set @d=@b.STCentroid().STBuffer(@c.STPointN(1).STDistance(@c.STPointN(3))+0.0005)
 set @i=@i+1;
end
select CAST(DATEDIFF(MS, @now,GETDATE()) as CHAR(10));
set @now=GETDATE();
set @i=0;
while @i<10
begin
 set @c=@a.STEnvelope();
 set @d=@b.STCentroid().STBuffer(@c.STPointN(1).STDistance(@c.STPointN(3))+0.0005)
 set @i=@i+1;
end
select CAST(DATEDIFF(MS, @now,GETDATE()) as CHAR(10));
result: first method: 350 ms second method:6 ms