/*******************************************************************************
*                                                                       
*N  {geom_distance.c}  -- demonstrates distance between   
*                       different shapes
*   
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*P  Purpose:
*    This sample C program demonstrates the distance between  
*    different shapes
*    
*E                                                                 
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* How to compile:: 
*	 Please refer section "Build C Samples" in the SDE sample
*
*E
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* Usage:
*     geom_distance {server} {instance} {database} {user} {password}
*
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*X  Legalese:
*
* Copyright � 2007 ESRI
*
* All rights reserved under the copyright laws of the United States and 
* applicable international laws, treaties, and conventions.
*
* You may freely redistribute and use this sample code, with or without 
* modification, provided you include the original copyright notice and use 
* restrictions.  
*
* Disclaimer:  THE SAMPLE CODE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 
* WARRANTIES, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ESRI OR 
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
* OR BUSINESS INTERRUPTION) SUSTAINED BY YOU OR A THIRD PARTY, HOWEVER CAUSED 
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
* TORT ARISING IN ANY WAY OUT OF THE USE OF THIS SAMPLE CODE, EVEN IF ADVISED 
* OF THE POSSIBILITY OF SUCH DAMAGE.
* 
* For additional information, contact:
* Environmental Systems Research Institute, Inc.
* Attn: Contracts and Legal Services Department
* 380 New York Street
* Redlands, California, 92373
* USA
* 
* email: contracts@esri.com
*
*E
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sdetype.h"
#include "sdeerno.h"

/* Function macros */
#define check_rc_return_on_failure(c,s,rc,f) \
	{if(rc!= SE_SUCCESS) {check_rc_(c,s,rc,f,__LINE__,__FILE__);return SE_FAILURE; }}
/* Local Function Prototypes */
void check_rc_(SE_CONNECTION Connection, SE_STREAM Stream, LONG rc, 
				 char *comment, LONG line_no, char* file_name) ;
static void S_print_shape(SE_SHAPE shp);

LONG main(int argc, char *argv[])
{
	CHAR   			*server, 
       	       		*user, 
					*passwd, 
					*database,
					*instance;
	SE_CONNECTION 	conn;
	SE_ERROR 		error;
	SE_COORDREF     coordref;
	SE_SHAPE        shp1,shp2;
	SE_ENVELOPE		env;
    SE_POINT		shp1_coords[10],shp2_coords[10];
	int				num_of_points,num_of_parts, part_offsets[10];
	LONG			result;
	LFLOAT			distance;

	if(argc<6){
		printf("Usage %s <server> <instance> <database> <user> <password>",argv[0]);
		exit(1);
	}

	server=argv[1];
	instance=argv[2];
	database=argv[3];
	user=argv[4];
	passwd=argv[5];

  	result = SE_connection_create( server, instance, database, user, passwd, &error, &conn );
	check_rc_return_on_failure (conn,NULL,result,"SE_connection_create");

	/*prepare two shape handles*/
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (NULL,NULL,result,"SE_coordref_create");
	result = SE_coordref_set_xy (coordref,0.0,0.0,1000.0);
	check_rc_return_on_failure (NULL,NULL,result,"SE_coordref_set_xy");
	result = SE_shape_create (coordref,&shp1);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_create");
	result = SE_shape_create (coordref,&shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_create");

	/********************************************************************
	* 1. Point Cases                                                    *
	*********************************************************************/
	/*distance between two overlapping points*/
	printf("\nDistance between two overlapping points:\n");
	shp1_coords[0].x=100.0;
	shp1_coords[0].y=100.0;
	num_of_points=1;
    result = SE_shape_generate_point(num_of_points,shp1_coords, NULL, NULL, shp1);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_point");
	//We will demostrate SE_shape_duplicate() and create a overlapping point
	result=SE_shape_duplicate (shp1, shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_duplicate");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	//In this sample, we will perform inside tests when calculating distances
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f \n",distance);
	
	/*distance between two non-overlapping points*/
	printf("\nDistance between two non-overlapping points:\n");
	shp2_coords[0].x=110.0;
	shp2_coords[0].y=180.0;
	num_of_points=1;
    result = SE_shape_generate_point(num_of_points,shp2_coords, NULL, NULL, shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_point");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f\n",distance);

	/*distance between a simple point and multipoint*/
	printf("\nDistance between a simple point and multipoint :\n");
	shp2_coords[0].x=150.0;
	shp2_coords[0].y=180.0;
	shp2_coords[1].x=130.0;
	shp2_coords[1].y=100.0;	
	num_of_points=2;
    result = SE_shape_generate_point(num_of_points,shp2_coords, NULL, NULL, shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_point");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f \n",distance);

	/*Distance between completely overlapping multipoint shapes*/
	printf("\nDistance between completely overlapping multipoint shapes:\n");
	shp1_coords[0].x=150.0;
	shp1_coords[0].y=180.0;
	shp1_coords[1].x=130.0;
	shp1_coords[1].y=100.0;	
	num_of_points=2;
    result = SE_shape_generate_point(num_of_points,shp1_coords, NULL, NULL, shp1);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_point");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f \n",distance);

	/*Distance between partially overlapping multipoint shapess*/
	printf("\nDistance between partially overlapping multipoint shapes:\n");
	shp2_coords[0].x=150.0;
	shp2_coords[0].y=180.0;
	shp2_coords[1].x=100.0;
	shp2_coords[1].y=100.0;	
	num_of_points=2;
    result = SE_shape_generate_point(num_of_points,shp2_coords, NULL, NULL, shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_point");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f \n",distance);

	/*Distance between non-overlapping multipoint shapes*/
	printf("\nDistance between non-overlapping multipoint shapes:\n");
	shp2_coords[0].x=140.0;
	shp2_coords[0].y=140.0;
	shp2_coords[1].x=160.0;
	shp2_coords[1].y=200.0;	
	shp2_coords[2].x=300.0;
	shp2_coords[2].y=120.0;
	shp2_coords[3].x=300.0;
	shp2_coords[3].y=150.0;	
	num_of_points=4;
    result = SE_shape_generate_point(num_of_points,shp2_coords, NULL, NULL, shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_point");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f \n",distance);

	/********************************************************************
	* 2. Line Cases                        v                            *
	*********************************************************************/
	/*Distance between overlapping simple line shapes*/
	printf("\nDistance between overlapping simple line shapes:\n");
	shp1_coords[0].x=100.0;
	shp1_coords[0].y=100.0;
	shp1_coords[1].x=200.0;
	shp1_coords[1].y=200.0;	
	shp1_coords[2].x=300.0;
	shp1_coords[2].y=100.0;
	num_of_points=3;
	num_of_parts=1;
	part_offsets[0]=0;
    result = SE_shape_generate_line(num_of_points, num_of_parts,
                part_offsets, shp1_coords, NULL, NULL, shp1);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_line");
	result=SE_shape_duplicate (shp1, shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_duplicate");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f \n",distance);


	/* Distance between partially overlapping simple line shapes*/
	printf("\nDistance between partially overlapping simple line shapes:\n");
	shp2_coords[0].x=200.0;
	shp2_coords[0].y=200.0;
	shp2_coords[1].x=300.0;
	shp2_coords[1].y=100.0;	
	shp2_coords[2].x=400.0;
	shp2_coords[2].y=100.0;
	num_of_points=3;
	num_of_parts=1;
	part_offsets[0]=0;
    result = SE_shape_generate_line(num_of_points, num_of_parts,
                part_offsets, shp2_coords, NULL, NULL, shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_line");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f \n",distance);

	/* Distance between non-overlapping simple line shapes*/
	printf("\nDistance between non-overlapping simple line shapes:\n");
	shp2_coords[0].x=300.0;
	shp2_coords[0].y=200.0;
	shp2_coords[1].x=400.0;
	shp2_coords[1].y=200.0;	
	shp2_coords[2].x=400.0;
	shp2_coords[2].y=100.0;
	num_of_points=3;
	num_of_parts=1;
	part_offsets[0]=0;
    result = SE_shape_generate_line(num_of_points, num_of_parts,
                part_offsets, shp2_coords, NULL, NULL, shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_line");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f\n",distance);

	/* Distance between overlapping simple line shapes*/
	printf("\nDistance between overlapping simple multi-line shapes:\n");
	shp1_coords[0].x=100.0;
	shp1_coords[0].y=100.0;
	shp1_coords[1].x=200.0;
	shp1_coords[1].y=200.0;	
	shp1_coords[2].x=300.0;
	shp1_coords[2].y=100.0;
	shp1_coords[3].x=400.0;
	shp1_coords[3].y=100.0;	
	shp1_coords[4].x=400.0;
	shp1_coords[4].y=200.0;
	num_of_points=5;
	num_of_parts=2;
	part_offsets[0]=0;
	part_offsets[1]=3;
    result = SE_shape_generate_line(num_of_points, num_of_parts,
                part_offsets, shp1_coords, NULL, NULL, shp1);

	shp2_coords[0].x=100.0;
	shp2_coords[0].y=100.0;
	shp2_coords[1].x=200.0;
	shp2_coords[1].y=200.0;	
	shp2_coords[2].x=300.0;
	shp2_coords[2].y=100.0;
	shp2_coords[3].x=400.0;
	shp2_coords[3].y=100.0;	
	shp2_coords[4].x=400.0;
	shp2_coords[4].y=200.0;
	num_of_points=5;
	num_of_parts=1;
	part_offsets[0]=0;
    result = SE_shape_generate_line(num_of_points, num_of_parts,
                part_offsets, shp2_coords, NULL, NULL, shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_line");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f \n",distance);

	/*  Distance between partially overlapping polygon shapes*/
	printf("\nDistance between partially overlapping polygon shapes:\n");
	shp1_coords[0].x=1.0;
	shp1_coords[0].y=3.0;
	shp1_coords[1].x=3.0;
	shp1_coords[1].y=1.0;	
	shp1_coords[2].x=6.0;
	shp1_coords[2].y=4.0;
	shp1_coords[3].x=4.0;
	shp1_coords[3].y=6.0;	
	shp1_coords[4].x=2.0;
	shp1_coords[4].y=5.0;
	shp1_coords[5].x=1.0;
	shp1_coords[5].y=3.0;
	num_of_points=6;
	num_of_parts=1;
	part_offsets[0]=0;
    result = SE_shape_generate_polygon(num_of_points, num_of_parts,
                part_offsets, shp1_coords, NULL, NULL, shp1);

	shp2_coords[0].x=4.0;
	shp2_coords[0].y=1.0;
	shp2_coords[1].x=6.0;
	shp2_coords[1].y=2.0;	
	shp2_coords[2].x=7.0;
	shp2_coords[2].y=5.0;
	shp2_coords[3].x=6.0;
	shp2_coords[3].y=6.0;	
	shp2_coords[4].x=4.0;
	shp2_coords[4].y=4.0;
	shp2_coords[5].x=4.0;
	shp2_coords[5].y=1.0;
	num_of_points=6;
	num_of_parts=1;
	part_offsets[0]=0;
    result = SE_shape_generate_polygon(num_of_points, num_of_parts,
                part_offsets, shp2_coords, NULL, NULL, shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_line");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f \n",distance);

	/* Distance between rectangles*/
	printf("\nDistance between rectangles:\n");
	env.minx=200.0;
	env.miny=200.0;
	env.maxx=400.0;
	env.maxy=400.0;
    result = SE_shape_generate_rectangle(&env,shp1);

	env.minx=600.0;
	env.miny=600.0;
	env.maxx=900.0;
	env.maxy=900.0;
    result = SE_shape_generate_rectangle(&env,shp2);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_line");
	printf("SHAPE1:");
	S_print_shape(shp1);
	printf("SHAPE2:");
	S_print_shape(shp2);
	result=SE_shape_calculate_distance (shp1, shp2,&distance,TRUE);
	check_rc_return_on_failure (NULL,NULL,result,"SE_shape_calculate_distance");
	printf("Distance=%-7.3f \n",distance);

	SE_coordref_free(coordref);
	SE_shape_free(shp1);
	SE_shape_free(shp2);

	return SE_SUCCESS;
}

/***********************************************************************
*
*N  {S_print_shapes}  -  print coordinates of a shape
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     print coordinates of a shape
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <shp>  ==  (SE_SHAPE) The shape to be printed.
*E
***********************************************************************/
static void S_print_shape(SE_SHAPE shp){
	LONG			result;
	CHAR			shp_desc[1024];
	LONG			shp_size;

	if(shp ==NULL)
		printf("NULL\n");
	else if(SE_shape_is_nil(shp))
		printf("nil shape\n");
	else{
		result=SE_shape_get_text_size(shp,&shp_size);
		result=SE_shape_as_text (shp,shp_size+1,shp_desc);
		printf("%s\n",shp_desc);
	}
}

/***********************************************************************
*
*N  {check_rc_}  -  check the returned code
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     Check returned sde error code and print the error messages.
***********************************************************************/
void check_rc_(SE_CONNECTION Connection, SE_STREAM Stream, LONG rc, 
				 char *comment, LONG line_no, char* file_name) 
{

	SE_ERROR	error;
	CHAR		error_string [SE_MAX_MESSAGE_LENGTH];
	LONG		temp_rc=SE_FAILURE;


	if ((rc != SE_SUCCESS) && (rc != SE_FINISHED)) 
	{
		error_string[0] = '\0';
		SE_error_get_string (rc, error_string);

	    printf ("%s encountered a %d error:\"%s\" \nat line %ld in file %s\n",comment, rc,error_string, line_no, file_name);

		/*Print extended error info, if any */
		if ((SE_DB_IO_ERROR == rc) | (SE_INVALID_WHERE == rc) | (SE_SSA_FUNCTION_ERROR == rc)) 
		{
			if (NULL != Stream) 
			{
				/* Assume this is a stream error */
				temp_rc = SE_stream_get_ext_error (Stream, &error);
			}else if (NULL != Connection) {
				/*Assume this is a connection error */
				temp_rc = SE_connection_get_ext_error (Connection, &error);
			}
			if (SE_SUCCESS == temp_rc)
			{
					printf("Extended error code: %d, extended error string:\n%s\n",
					error.ext_error, error.err_msg1);
			}
		} /*End SE_DB_IO_ERROR */

	} 
}